diff --git a/app/build.gradle b/app/build.gradle index cb882817..881a6bdb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { applicationId "com.f0x1d.logfox" minSdk 21 targetSdk 33 - versionCode 21 - versionName "1.2.0" + versionCode 22 + versionName "1.2.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/com/f0x1d/logfox/adapter/CrashesAdapter.kt b/app/src/main/java/com/f0x1d/logfox/adapter/CrashesAdapter.kt index 3408190a..c13f17c9 100644 --- a/app/src/main/java/com/f0x1d/logfox/adapter/CrashesAdapter.kt +++ b/app/src/main/java/com/f0x1d/logfox/adapter/CrashesAdapter.kt @@ -9,10 +9,6 @@ import com.f0x1d.logfox.ui.viewholder.CrashViewHolder class CrashesAdapter(private val click: (AppCrash) -> Unit, private val delete: (AppCrash) -> Unit): BaseAdapter() { - init { - setHasStableIds(true) - } - override fun createHolder(layoutInflater: LayoutInflater, parent: ViewGroup) = CrashViewHolder( ItemCrashBinding.inflate(layoutInflater, parent, false), click, diff --git a/app/src/main/java/com/f0x1d/logfox/adapter/FiltersAdapter.kt b/app/src/main/java/com/f0x1d/logfox/adapter/FiltersAdapter.kt index 7ea5a873..692e1aa3 100644 --- a/app/src/main/java/com/f0x1d/logfox/adapter/FiltersAdapter.kt +++ b/app/src/main/java/com/f0x1d/logfox/adapter/FiltersAdapter.kt @@ -11,10 +11,6 @@ class FiltersAdapter(private val click: (UserFilter) -> Unit, private val delete: (UserFilter) -> Unit, private val checked: (UserFilter, Boolean) -> Unit): BaseAdapter() { - init { - setHasStableIds(true) - } - override fun createHolder(layoutInflater: LayoutInflater, parent: ViewGroup) = FilterViewHolder( ItemFilterBinding.inflate(layoutInflater, parent, false), click, diff --git a/app/src/main/java/com/f0x1d/logfox/adapter/LogsAdapter.kt b/app/src/main/java/com/f0x1d/logfox/adapter/LogsAdapter.kt index 2ad57112..8cfe5931 100644 --- a/app/src/main/java/com/f0x1d/logfox/adapter/LogsAdapter.kt +++ b/app/src/main/java/com/f0x1d/logfox/adapter/LogsAdapter.kt @@ -30,6 +30,10 @@ class LogsAdapter: BaseAdapter() { notifyItemRangeChanged(0, itemCount) } + init { + setHasStableIds(false) + } + override fun createHolder(layoutInflater: LayoutInflater, parent: ViewGroup) = LogViewHolder( ItemLogBinding.inflate(layoutInflater, parent, false) ) diff --git a/app/src/main/java/com/f0x1d/logfox/adapter/RecordingsAdapter.kt b/app/src/main/java/com/f0x1d/logfox/adapter/RecordingsAdapter.kt index 58a18045..ef5d386b 100644 --- a/app/src/main/java/com/f0x1d/logfox/adapter/RecordingsAdapter.kt +++ b/app/src/main/java/com/f0x1d/logfox/adapter/RecordingsAdapter.kt @@ -9,10 +9,6 @@ import com.f0x1d.logfox.ui.viewholder.RecordingViewHolder class RecordingsAdapter(private val click: (LogRecording) -> Unit, private val delete: (LogRecording) -> Unit): BaseAdapter() { - init { - setHasStableIds(true) - } - override fun createHolder(layoutInflater: LayoutInflater, parent: ViewGroup) = RecordingViewHolder( ItemRecordingBinding.inflate(layoutInflater, parent, false), click, diff --git a/app/src/main/java/com/f0x1d/logfox/adapter/base/BaseAdapter.kt b/app/src/main/java/com/f0x1d/logfox/adapter/base/BaseAdapter.kt index 8c580e4e..638929ea 100644 --- a/app/src/main/java/com/f0x1d/logfox/adapter/base/BaseAdapter.kt +++ b/app/src/main/java/com/f0x1d/logfox/adapter/base/BaseAdapter.kt @@ -18,6 +18,10 @@ abstract class BaseAdapter: RecyclerView.Adapter override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createHolder( diff --git a/app/src/main/java/com/f0x1d/logfox/database/AppDatabase.kt b/app/src/main/java/com/f0x1d/logfox/database/AppDatabase.kt index 9161afcf..45e90486 100644 --- a/app/src/main/java/com/f0x1d/logfox/database/AppDatabase.kt +++ b/app/src/main/java/com/f0x1d/logfox/database/AppDatabase.kt @@ -5,8 +5,10 @@ import androidx.room.RoomDatabase import androidx.room.TypeConverters import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase +import com.f0x1d.logfox.LogFoxApp +import com.f0x1d.logfox.R -@Database(entities = [AppCrash::class, LogRecording::class, UserFilter::class], version = 6) +@Database(entities = [AppCrash::class, LogRecording::class, UserFilter::class], version = 7) @TypeConverters(CrashTypeConverter::class, AllowedLevelsConverter::class) abstract class AppDatabase: RoomDatabase() { @@ -33,6 +35,12 @@ abstract class AppDatabase: RoomDatabase() { database.execSQL("CREATE TABLE LogRecording(id INTEGER PRIMARY KEY ASC AUTOINCREMENT NOT NULL, date_and_time INTEGER NOT NULL, file TEXT NOT NULL)") } } + val MIGRATION_6_7 = object : Migration(6, 7) { + override fun migrate(database: SupportSQLiteDatabase) { + val recordingString = LogFoxApp.instance.getString(R.string.recording) + database.execSQL("ALTER TABLE LogRecording ADD COLUMN title TEXT NOT NULL DEFAULT '${recordingString}'") + } + } } abstract fun appCrashDao(): AppCrashDao diff --git a/app/src/main/java/com/f0x1d/logfox/database/LogRecording.kt b/app/src/main/java/com/f0x1d/logfox/database/LogRecording.kt index ba57bccd..30fd8c19 100644 --- a/app/src/main/java/com/f0x1d/logfox/database/LogRecording.kt +++ b/app/src/main/java/com/f0x1d/logfox/database/LogRecording.kt @@ -5,7 +5,8 @@ import kotlinx.coroutines.flow.Flow import java.io.File @Entity -data class LogRecording(@ColumnInfo(name = "date_and_time") val dateAndTime: Long, +data class LogRecording(@ColumnInfo(name = "title") val title: String, + @ColumnInfo(name = "date_and_time") val dateAndTime: Long, @ColumnInfo(name = "file") val file: String, @PrimaryKey(autoGenerate = true) val id: Long = 0) { @@ -24,6 +25,9 @@ interface LogRecordingDao { @Insert fun insert(logRecording: LogRecording): Long + @Update + fun update(logRecording: LogRecording) + @Delete fun delete(logRecording: LogRecording) diff --git a/app/src/main/java/com/f0x1d/logfox/di/RoomModule.kt b/app/src/main/java/com/f0x1d/logfox/di/RoomModule.kt index ea5abf3d..c4695c0e 100644 --- a/app/src/main/java/com/f0x1d/logfox/di/RoomModule.kt +++ b/app/src/main/java/com/f0x1d/logfox/di/RoomModule.kt @@ -22,6 +22,7 @@ object RoomModule { AppDatabase.MIGRATION_2_3, AppDatabase.MIGRATION_3_4, AppDatabase.MIGRATION_4_5, - AppDatabase.MIGRATION_5_6 + AppDatabase.MIGRATION_5_6, + AppDatabase.MIGRATION_6_7 ).build() } \ No newline at end of file diff --git a/app/src/main/java/com/f0x1d/logfox/extensions/ViewInsetsExtensions.kt b/app/src/main/java/com/f0x1d/logfox/extensions/ViewInsetsExtensions.kt index b91d57a9..64ef8a85 100644 --- a/app/src/main/java/com/f0x1d/logfox/extensions/ViewInsetsExtensions.kt +++ b/app/src/main/java/com/f0x1d/logfox/extensions/ViewInsetsExtensions.kt @@ -19,11 +19,15 @@ fun View.applyBottomInsets(view: View) = applyInsets(view) { insets -> } } -fun View.applyInsets(view: View, block: View.(Insets) -> Unit) { +fun View.applyInsets(view: View, block: View.(Insets) -> Unit) = com.f0x1d.logfox.extensions.applyInsets(view) { + block.invoke(this, it) +} + +fun applyInsets(view: View, block: (Insets) -> Unit) { ViewCompat.setOnApplyWindowInsetsListener(view) { _, windowInsets -> val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) - block.invoke(this, insets) + block.invoke(insets) windowInsets } diff --git a/app/src/main/java/com/f0x1d/logfox/extensions/ViewModelExtensions.kt b/app/src/main/java/com/f0x1d/logfox/extensions/ViewModelExtensions.kt index f19968f9..395fd2a7 100644 --- a/app/src/main/java/com/f0x1d/logfox/extensions/ViewModelExtensions.kt +++ b/app/src/main/java/com/f0x1d/logfox/extensions/ViewModelExtensions.kt @@ -2,15 +2,27 @@ package com.f0x1d.logfox.extensions import android.net.Uri import androidx.lifecycle.viewModelScope +import com.f0x1d.logfox.utils.exportCrashToZip import com.f0x1d.logfox.utils.exportLogToZip import com.f0x1d.logfox.viewmodel.base.BaseFlowProxyViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import java.io.OutputStream -inline fun BaseFlowProxyViewModel.logToZip(uri: Uri, crossinline block: R.() -> String) { +inline fun BaseFlowProxyViewModel.logToZip(uri: Uri, crossinline block: R.() -> String) = toZip(uri) { + exportLogToZip(ctx, block.invoke(it)) +} + +inline fun BaseFlowProxyViewModel.crashToZip(uri: Uri, crossinline block: R.() -> String) = toZip(uri) { + exportCrashToZip(ctx, block.invoke(it)) +} + +inline fun BaseFlowProxyViewModel.toZip(uri: Uri, crossinline block: OutputStream.(R) -> Unit) { viewModelScope.launch(Dispatchers.IO) { data.value?.apply { - ctx.contentResolver.openOutputStream(uri)?.exportLogToZip(ctx, block.invoke(this)) + ctx.contentResolver.openOutputStream(uri)?.also { + block.invoke(it, this) + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/f0x1d/logfox/repository/logging/RecordingsRepository.kt b/app/src/main/java/com/f0x1d/logfox/repository/logging/RecordingsRepository.kt index ff2bb3eb..b158bb0b 100644 --- a/app/src/main/java/com/f0x1d/logfox/repository/logging/RecordingsRepository.kt +++ b/app/src/main/java/com/f0x1d/logfox/repository/logging/RecordingsRepository.kt @@ -1,6 +1,7 @@ package com.f0x1d.logfox.repository.logging import android.content.Context +import com.f0x1d.logfox.R import com.f0x1d.logfox.database.AppDatabase import com.f0x1d.logfox.database.LogRecording import com.f0x1d.logfox.extensions.exportFormatted @@ -118,7 +119,9 @@ class RecordingsRepository @Inject constructor(@ApplicationContext private val c writeLogsToFile() recordingsFlow.updateList { - val logRecording = LogRecording(recordingTime, recordingFile!!.absolutePath).run { + val title = "${context.getString(R.string.recording)} ${recordingsFlow.value.size + 1}" + + val logRecording = LogRecording(title, recordingTime, recordingFile!!.absolutePath).run { copy(id = database.logRecordingDao().insert(this)) } @@ -133,6 +136,17 @@ class RecordingsRepository @Inject constructor(@ApplicationContext private val c } } + fun updateTitle(logRecording: LogRecording, newTitle: String) { + onAppScope { + recordingsFlow.updateList { + val newValue = logRecording.copy(title = newTitle).also { + database.logRecordingDao().update(it) + } + set(indexOfFirst { it.id == newValue.id }, newValue) + } + } + } + fun deleteRecording(logRecording: LogRecording) { onAppScope { recordingsFlow.updateList { diff --git a/app/src/main/java/com/f0x1d/logfox/ui/activity/CrashDetailsActivity.kt b/app/src/main/java/com/f0x1d/logfox/ui/activity/CrashDetailsActivity.kt index 0041b2a6..a418279b 100644 --- a/app/src/main/java/com/f0x1d/logfox/ui/activity/CrashDetailsActivity.kt +++ b/app/src/main/java/com/f0x1d/logfox/ui/activity/CrashDetailsActivity.kt @@ -30,7 +30,7 @@ class CrashDetailsActivity: BaseViewModelActivity() diff --git a/app/src/main/java/com/f0x1d/logfox/ui/dialog/RecordingBottomSheet.kt b/app/src/main/java/com/f0x1d/logfox/ui/dialog/RecordingBottomSheet.kt index 18a1db29..0b97fa80 100644 --- a/app/src/main/java/com/f0x1d/logfox/ui/dialog/RecordingBottomSheet.kt +++ b/app/src/main/java/com/f0x1d/logfox/ui/dialog/RecordingBottomSheet.kt @@ -13,6 +13,8 @@ import com.f0x1d.logfox.extensions.logToZip import com.f0x1d.logfox.extensions.shareFileIntent import com.f0x1d.logfox.extensions.toLocaleString import com.f0x1d.logfox.ui.dialog.base.BaseViewModelBottomSheet +import com.f0x1d.logfox.utils.OneTimeAction +import com.f0x1d.logfox.utils.view.PauseTextWatcher import com.f0x1d.logfox.utils.viewModelFactory import com.f0x1d.logfox.viewmodel.recordings.RecordingViewModel import com.f0x1d.logfox.viewmodel.recordings.RecordingViewModelAssistedFactory @@ -33,7 +35,7 @@ class RecordingBottomSheet: BaseViewModelBottomSheet if (logRecording == null) return@observe - binding.title.text = logRecording.dateAndTime.toLocaleString() + setTextAction.doIfNotDone { + pauseTextWatcher.paused { + binding.title.setText(logRecording.title) + } + } + + binding.timeText.text = logRecording.dateAndTime.toLocaleString() binding.exportLayout.setOnClickListener { logExportLauncher.launch("${logRecording.dateAndTime.exportFormatted}.txt") diff --git a/app/src/main/java/com/f0x1d/logfox/ui/fragment/FiltersFragment.kt b/app/src/main/java/com/f0x1d/logfox/ui/fragment/FiltersFragment.kt index e5ae7833..e96811e4 100644 --- a/app/src/main/java/com/f0x1d/logfox/ui/fragment/FiltersFragment.kt +++ b/app/src/main/java/com/f0x1d/logfox/ui/fragment/FiltersFragment.kt @@ -5,7 +5,9 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.ViewGroup.MarginLayoutParams import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import androidx.fragment.app.viewModels import androidx.hilt.navigation.fragment.hiltNavGraphViewModels @@ -17,6 +19,7 @@ import com.f0x1d.logfox.databinding.FragmentFiltersBinding import com.f0x1d.logfox.extensions.applyInsets import com.f0x1d.logfox.extensions.setClickListenerOn import com.f0x1d.logfox.ui.fragment.base.BaseViewModelFragment +import com.f0x1d.logfox.utils.dpToPx import com.f0x1d.logfox.viewmodel.LogsViewModel import com.f0x1d.logfox.viewmodel.filters.FiltersViewModel import dagger.hilt.android.AndroidEntryPoint @@ -47,16 +50,17 @@ class FiltersFragment: BaseViewModelFragment - updatePadding(bottom = insets.bottom) + applyInsets(view) { insets -> + binding.addFab.updateLayoutParams { + bottomMargin = 10.dpToPx.toInt() + insets.bottom + } + + binding.filtersRecycler.updatePadding(bottom = 71.dpToPx.toInt() + insets.bottom) } binding.toolbar.setOnClickListener { findNavController().popBackStack() } binding.toolbar.inflateMenu(R.menu.filters_menu) binding.toolbar.menu.apply { - setClickListenerOn(R.id.create_item) { - findNavController().navigate(FiltersFragmentDirections.actionFiltersFragmentToFilterBottomSheet()) - } setClickListenerOn(R.id.clear_item) { viewModel.clearAll() } @@ -71,6 +75,10 @@ class FiltersFragment: BaseViewModelFragment) { close() } -fun OutputStream.exportLogToZip(context: Context, log: String) { +fun OutputStream.exportCrashToZip(context: Context, log: String) = exportToZip(context) { + putZipEntry("log.txt", log.encodeToByteArray()) +} + +fun OutputStream.exportLogToZip(context: Context, logFile: String) = exportToZip(context) { + putZipEntry("log.txt", File(logFile)) +} + +private fun OutputStream.exportToZip(context: Context, block: ZipOutputStream.() -> Unit) { val device = EntryPointAccessors.fromApplication(context, ExportImportUtilsEntryPoint::class.java).device() ZipOutputStream(this).apply { - putZipEntry("log.txt", log.encodeToByteArray()) + block.invoke(this) putZipEntry("device.txt", device.toString().encodeToByteArray()) close() @@ -53,6 +63,18 @@ private fun ZipOutputStream.putZipEntry(name: String, content: ByteArray) { closeEntry() } +private fun ZipOutputStream.putZipEntry(name: String, file: File) { + val entry = ZipEntry(name) + putNextEntry(entry) + + with(FileInputStream(file)) { + copyTo(this@putZipEntry) + close() + } + + closeEntry() +} + @EntryPoint @InstallIn(SingletonComponent::class) interface ExportImportUtilsEntryPoint { diff --git a/app/src/main/java/com/f0x1d/logfox/utils/OneTimeAction.kt b/app/src/main/java/com/f0x1d/logfox/utils/OneTimeAction.kt new file mode 100644 index 00000000..b205217f --- /dev/null +++ b/app/src/main/java/com/f0x1d/logfox/utils/OneTimeAction.kt @@ -0,0 +1,13 @@ +package com.f0x1d.logfox.utils + +class OneTimeAction { + + private var done = false + + fun doIfNotDone(action: () -> Unit) { + if (!done) { + action.invoke() + done = true + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/f0x1d/logfox/utils/view/FontsInterceptor.kt b/app/src/main/java/com/f0x1d/logfox/utils/view/FontsInterceptor.kt index 7004ab88..9f379305 100644 --- a/app/src/main/java/com/f0x1d/logfox/utils/view/FontsInterceptor.kt +++ b/app/src/main/java/com/f0x1d/logfox/utils/view/FontsInterceptor.kt @@ -16,14 +16,14 @@ class FontsInterceptor(context: Context): Interceptor { R.id.title to boldSansTypeface, R.id.app_name to boldSansTypeface, android.R.id.title to boldSansTypeface, - R.id.recording_text to boldSansTypeface, R.id.delete_button to boldSansTypeface, R.id.root_button to boldSansTypeface, R.id.adb_button to boldSansTypeface, R.id.search_button to boldSansTypeface, R.id.clear_search_button to boldSansTypeface, R.id.log_levels_button to boldSansTypeface, - R.id.save_button to boldSansTypeface + R.id.save_button to boldSansTypeface, + R.id.time_text to boldSansTypeface ) override fun intercept(chain: Interceptor.Chain): InflateResult { diff --git a/app/src/main/java/com/f0x1d/logfox/utils/view/PauseTextWatcher.kt b/app/src/main/java/com/f0x1d/logfox/utils/view/PauseTextWatcher.kt new file mode 100644 index 00000000..33c41cbe --- /dev/null +++ b/app/src/main/java/com/f0x1d/logfox/utils/view/PauseTextWatcher.kt @@ -0,0 +1,21 @@ +package com.f0x1d.logfox.utils.view + +import android.text.Editable +import android.text.TextWatcher + +class PauseTextWatcher(private val listener: (Editable?) -> Unit): TextWatcher { + + var paused = false + + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} + override fun afterTextChanged(editable: Editable?) { + if (!paused) listener.invoke(editable) + } + + fun paused(block: () -> Unit) { + paused = true + block.invoke() + paused = false + } +} \ No newline at end of file diff --git a/app/src/main/java/com/f0x1d/logfox/viewmodel/recordings/RecordingViewModel.kt b/app/src/main/java/com/f0x1d/logfox/viewmodel/recordings/RecordingViewModel.kt index 963dfe42..107834ec 100644 --- a/app/src/main/java/com/f0x1d/logfox/viewmodel/recordings/RecordingViewModel.kt +++ b/app/src/main/java/com/f0x1d/logfox/viewmodel/recordings/RecordingViewModel.kt @@ -5,6 +5,7 @@ import android.net.Uri import androidx.lifecycle.viewModelScope import com.f0x1d.logfox.database.AppDatabase import com.f0x1d.logfox.database.LogRecording +import com.f0x1d.logfox.repository.logging.RecordingsRepository import com.f0x1d.logfox.viewmodel.base.BaseSameFlowProxyViewModel import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -15,7 +16,8 @@ import java.io.File class RecordingViewModel @AssistedInject constructor(application: Application, database: AppDatabase, - @Assisted private val recordingId: Long): BaseSameFlowProxyViewModel( + @Assisted private val recordingId: Long, + private val recordingsRepository: RecordingsRepository): BaseSameFlowProxyViewModel( application, database.logRecordingDao().get(recordingId) ) { @@ -27,6 +29,10 @@ class RecordingViewModel @AssistedInject constructor(application: Application, close() } } + + fun updateTitle(title: String) = data.value?.apply { + recordingsRepository.updateTitle(this, title) + } } @AssistedFactory diff --git a/app/src/main/res/layout/fragment_filters.xml b/app/src/main/res/layout/fragment_filters.xml index f1c86d72..73ca2a41 100644 --- a/app/src/main/res/layout/fragment_filters.xml +++ b/app/src/main/res/layout/fragment_filters.xml @@ -26,7 +26,15 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" - android:paddingBottom="10dp" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_recordings.xml b/app/src/main/res/layout/fragment_recordings.xml index 3431ea1c..1dc2cc19 100644 --- a/app/src/main/res/layout/fragment_recordings.xml +++ b/app/src/main/res/layout/fragment_recordings.xml @@ -23,6 +23,8 @@ android:id="@+id/recordings_recycler" android:layout_width="match_parent" android:layout_height="match_parent" + android:clipToPadding="false" + android:paddingBottom="66dp" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> + android:background="?selectableItemBackground" + xmlns:app="http://schemas.android.com/apk/res-auto"> + app:layout_constraintBottom_toTopOf="@id/date_text"/> + + diff --git a/app/src/main/res/layout/sheet_recording.xml b/app/src/main/res/layout/sheet_recording.xml index a34b3e35..460c95ff 100644 --- a/app/src/main/res/layout/sheet_recording.xml +++ b/app/src/main/res/layout/sheet_recording.xml @@ -5,7 +5,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> + app:layout_constraintBottom_toTopOf="@id/title_layout"/> + + + + + diff --git a/app/src/main/res/menu/filters_menu.xml b/app/src/main/res/menu/filters_menu.xml index b6c63fe2..39611f9a 100644 --- a/app/src/main/res/menu/filters_menu.xml +++ b/app/src/main/res/menu/filters_menu.xml @@ -2,17 +2,10 @@ - - + app:showAsAction="never" /> Запустить сервис Остановить сервис Сервис нужен для сбора сбоев в фоне, без него Android просто закроет LogFox + Запись + Название \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f2f366eb..2044d32a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -84,4 +84,6 @@ Start service Stop service Service is required to observe crashes in background. Without service Android kills LogFox + Recording + Title \ No newline at end of file