diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 87459d3..ad137e1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,7 +7,8 @@ - + + (R.id.cbPersonalised) val helpClasses = findViewById(R.id.chipHelpClasses) val helpCourses = findViewById(R.id.chipHelpCourses) + val greeting = findViewById(R.id.cbGreetings) helpClasses.setOnClickListener { createDialog(getString(R.string.enterGradeHelpTitle), getString( @@ -92,6 +94,23 @@ internal class FirstTime : AppCompatActivity(R.layout.activity_first_time) { val inflater = this.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater +// findViewById(R.id.btnRestoreFromFile).setOnClickListener { +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { +// requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 42) +// } +// HelperFunctions.readPrefsFromXml(prefs) +// name.setText(prefs.getString("username", "")) +// grade.setText(prefs.getString("classes", "")) +// courses.setText(prefs.getString("courses", "")) +// notif.isChecked = prefs.getBoolean("notif", false) +// dark.isChecked = when (prefs.getInt("themeInt", 0)) { +// 0 -> true +// else -> false +// } +// greeting.isChecked = prefs.getBoolean("greeting", false) +// pers.isChecked = prefs.getBoolean("defaultPersonalised", false) +// } + fab.setOnClickListener { fab.isClickable = false @@ -105,7 +124,7 @@ internal class FirstTime : AppCompatActivity(R.layout.activity_first_time) { edit.putInt("themeInt", 0) } edit.putBoolean("notif", notif.isChecked) - .putBoolean("greeting", findViewById(R.id.cbGreetings).isChecked) + .putBoolean("greeting", greeting.isChecked) .putBoolean("defaultPersonalised", pers.isChecked) .putBoolean("firstTime", false) .putBoolean("colourTransferred", true) @@ -116,7 +135,7 @@ internal class FirstTime : AppCompatActivity(R.layout.activity_first_time) { val x: Int = fab.right - fab.width / 2 val y: Int = fab.bottom- fab.height / 2 - val endRadius = Math.hypot(cLayout.width.toDouble(), cLayout.height.toDouble()).toInt() + val endRadius = hypot(cLayout.width.toDouble(), cLayout.height.toDouble()).toInt() inflater.inflate(R.layout.welcome_screen, linearInflation, true) val anim = ViewAnimationUtils.createCircularReveal(linearInflation, x, y, 0F, endRadius.toFloat()) val handler = Handler() diff --git a/app/src/main/java/com/denizd/substitutionplan/activities/Main.kt b/app/src/main/java/com/denizd/substitutionplan/activities/Main.kt index 6df93c3..845c318 100644 --- a/app/src/main/java/com/denizd/substitutionplan/activities/Main.kt +++ b/app/src/main/java/com/denizd/substitutionplan/activities/Main.kt @@ -20,7 +20,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import androidx.recyclerview.widget.RecyclerView import com.crashlytics.android.Crashlytics -import com.denizd.substitutionplan.data.MiscData +import com.denizd.substitutionplan.data.HelperFunctions import com.denizd.substitutionplan.R import com.denizd.substitutionplan.fragments.FoodFragment import com.denizd.substitutionplan.fragments.GeneralPlanFragment @@ -30,6 +30,7 @@ import com.denizd.substitutionplan.services.FBPingService import com.google.android.material.appbar.AppBarLayout import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.snackbar.Snackbar +import com.google.firebase.FirebaseApp import com.jaredrummler.android.device.DeviceName import java.lang.IllegalArgumentException import java.util.* @@ -54,13 +55,14 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) { } else { if (!prefs.getBoolean("colourTransferred", false)) { - MiscData.transferOldColourIntsToString(prefs) + HelperFunctions.transferOldColourIntsToString(prefs) edit.putBoolean("colourTransferred", true).apply() } edit.putInt("launchDev", prefs.getInt("launchDev", 0) + 1) edit.apply() + FirebaseApp.initializeApp(this) pingFirebaseTopics() val appbarlayout = findViewById(R.id.appbarlayout) @@ -119,10 +121,7 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) { if (!prefs.getBoolean("autoRefresh", false) && prefs.getInt("firstTimeOpening", 0) != 0) { try { - val sb = StringBuilder() - val updated = sb.append(getText(R.string.lastUpdated)).append(prefs.getString("timeNew", "")).toString() - - Snackbar.make(contextView, updated, Snackbar.LENGTH_LONG).show() + Snackbar.make(contextView, "${getString(R.string.lastUpdated)} ${prefs.getString("timeNew", "")}", Snackbar.LENGTH_LONG).show() } catch (e: IllegalArgumentException) {} } diff --git a/app/src/main/java/com/denizd/substitutionplan/adapters/CardAdapter.kt b/app/src/main/java/com/denizd/substitutionplan/adapters/CardAdapter.kt index 5b0f1da..71dc89c 100644 --- a/app/src/main/java/com/denizd/substitutionplan/adapters/CardAdapter.kt +++ b/app/src/main/java/com/denizd/substitutionplan/adapters/CardAdapter.kt @@ -14,7 +14,7 @@ import android.widget.Toast import androidx.browser.customtabs.CustomTabsIntent import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView -import com.denizd.substitutionplan.data.MiscData +import com.denizd.substitutionplan.data.HelperFunctions import com.denizd.substitutionplan.R import com.denizd.substitutionplan.models.Subst import com.google.android.material.card.MaterialCardView @@ -74,7 +74,7 @@ internal class CardAdapter(private var mSubst: List) : RecyclerView.Adapt } holder.mImageView.setImageResource( - MiscData.getIconForCourse( + HelperFunctions.getIconForCourse( currentItem.course ) ) @@ -105,7 +105,7 @@ internal class CardAdapter(private var mSubst: List) : RecyclerView.Adapt } else { "" } - colour = MiscData.getColourForString(colourPrefsInt) + colour = HelperFunctions.getColourForString(colourPrefsInt) if (colour != 0) { holder.mCard.setCardBackgroundColor(ContextCompat.getColor(holder.mCourse.context, colour)) } else { diff --git a/app/src/main/java/com/denizd/substitutionplan/data/DataFetcher.kt b/app/src/main/java/com/denizd/substitutionplan/data/DataFetcher.kt index 2b1ff90..948826d 100644 --- a/app/src/main/java/com/denizd/substitutionplan/data/DataFetcher.kt +++ b/app/src/main/java/com/denizd/substitutionplan/data/DataFetcher.kt @@ -166,7 +166,7 @@ internal class DataFetcher(isPlan: Boolean, isMenu: Boolean, isJobService: Boole if (jobService && prefs.getBoolean("notif", true)) { substArray.filter { substitution -> - MiscData.checkPersonalSubstitutions( + HelperFunctions.checkPersonalSubstitutions( substitution, coursePreference, classPreference, @@ -202,10 +202,10 @@ internal class DataFetcher(isPlan: Boolean, isMenu: Boolean, isJobService: Boole val manager = mContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - MiscData.getNotificationChannel(mContext, prefs) + HelperFunctions.getNotificationChannel(mContext, prefs) val notification = NotificationCompat.Builder(mContext, - MiscData.notificationChannelId + HelperFunctions.notificationChannelId ) .setStyle(NotificationCompat.DecoratedCustomViewStyle()) .setCustomContentView(notificationLayout) diff --git a/app/src/main/java/com/denizd/substitutionplan/data/MiscData.kt b/app/src/main/java/com/denizd/substitutionplan/data/HelperFunctions.kt similarity index 60% rename from app/src/main/java/com/denizd/substitutionplan/data/MiscData.kt rename to app/src/main/java/com/denizd/substitutionplan/data/HelperFunctions.kt index 9b05ea6..1906ce2 100644 --- a/app/src/main/java/com/denizd/substitutionplan/data/MiscData.kt +++ b/app/src/main/java/com/denizd/substitutionplan/data/HelperFunctions.kt @@ -1,16 +1,29 @@ package com.denizd.substitutionplan.data +import android.Manifest import android.annotation.TargetApi import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context import android.content.SharedPreferences +import android.content.pm.PackageManager import android.graphics.Color +import android.os.Environment +import android.util.Log +import android.widget.Toast +import androidx.core.app.ActivityCompat +import androidx.core.app.ActivityCompat.requestPermissions +import androidx.core.content.ContextCompat.checkSelfPermission +import androidx.fragment.app.FragmentActivity import com.denizd.substitutionplan.R import com.denizd.substitutionplan.models.Subst import java.util.* +import java.io.File +import java.io.FileOutputStream +import java.io.OutputStreamWriter +import javax.xml.parsers.DocumentBuilderFactory -internal object MiscData { +internal object HelperFunctions { val languageIndependentCourses = arrayOf("German", "English", "French", "Spanish", "Latin", "Turkish", "Chinese", "Arts", "Music", "Theatre", "Geography", "History", "Politics", "Philosophy", "Religion", "Maths", "Biology", "Chemistry", @@ -164,4 +177,86 @@ internal object MiscData { manager.getNotificationChannel(notificationChannelId) } } + + private val prefKeys = arrayOf("username", "classes", "courses", "greeting", "themeInt", "notif", + "defaultPersonalised", "autoRefresh", "firstTimeDev", "launchDev", "pingFB", + "subscribedToFBDebugChannel", "subscribedToiOSChannel") + private val prefTypes = arrayOf("string", "string", "string", "bool", "int", "bool", "bool", "bool", + "string", "int", "int", "bool", "bool") + + private fun getPrefValue(prefs: SharedPreferences, type: String, key: String): Any { + return when (type) { + "string" -> prefs.getString(key, "") + "int" -> prefs.getInt(key, 0) + "bool" -> prefs.getBoolean(key, false) + else -> "" + } + } + + private fun setPrefValue(prefs: SharedPreferences, key: String, value: String, type: String) { + when (type) { + "int" -> prefs.edit().putInt(key, value.toInt()).apply() + "string" -> prefs.edit().putString(key, value).apply() + "bool" -> prefs.edit().putBoolean(key, value.toBoolean()).apply() + } + } + + fun writePrefsToXml(prefs: SharedPreferences, context: Context, activity: FragmentActivity) { + if (checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + val localPrefKeys = ArrayList() + val localPrefTypes = ArrayList() + for (i in prefKeys.indices) { + localPrefKeys.add(prefKeys[i]) + localPrefTypes.add(prefTypes[i]) + } + for (i in languageIndependentCourses.indices) { + localPrefKeys.add("card${languageIndependentCourses[i]}") + localPrefTypes.add("string") + } + val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + val file = File(dir, "avh_plan_data.xml") + val out = OutputStreamWriter(FileOutputStream(file, false)) + + var input = "\n" + for (i in localPrefKeys.indices) { + input += "\n\t${localPrefKeys[i]}" + + "\n\t${getPrefValue(prefs, localPrefTypes[i], localPrefKeys[i])}" + } + input += "\n" + out.write(input) + out.flush() + out.close() + Toast.makeText(context, context.getString(R.string.success), Toast.LENGTH_LONG).show() + } else { + Toast.makeText(context, context.getString(R.string.permissionDenied), Toast.LENGTH_LONG).show() + requestPermissions(activity, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 42) + } + } + + fun readPrefsFromXml(prefs: SharedPreferences, context: Context, activity: FragmentActivity) { + if (checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + val localPrefTypes = ArrayList() + for (i in prefKeys.indices) { + localPrefTypes.add(prefTypes[i]) + } + for (i in languageIndependentCourses.indices) { + localPrefTypes.add("string") + } + val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + val file = File(dir, "avh_plan_data.xml") + val documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder() + val document = documentBuilder.parse(file) + + for (i in localPrefTypes.indices) { + val key = document.getElementsByTagName("key").item(i).textContent + val value = document.getElementsByTagName("value").item(i).textContent + Log.d("VALUES", "$key $value") + setPrefValue(prefs, key, value, localPrefTypes[i]) + } + Toast.makeText(context, context.getString(R.string.success), Toast.LENGTH_LONG).show() + } else { + Toast.makeText(context, context.getString(R.string.permissionDenied), Toast.LENGTH_LONG).show() + requestPermissions(activity, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 42) + } + } } diff --git a/app/src/main/java/com/denizd/substitutionplan/fragments/PersonalPlanFragment.kt b/app/src/main/java/com/denizd/substitutionplan/fragments/PersonalPlanFragment.kt index 5e51384..5cd7db5 100644 --- a/app/src/main/java/com/denizd/substitutionplan/fragments/PersonalPlanFragment.kt +++ b/app/src/main/java/com/denizd/substitutionplan/fragments/PersonalPlanFragment.kt @@ -3,7 +3,7 @@ package com.denizd.substitutionplan.fragments import android.os.Bundle import android.view.View import androidx.lifecycle.Observer -import com.denizd.substitutionplan.data.MiscData +import com.denizd.substitutionplan.data.HelperFunctions import com.denizd.substitutionplan.R import com.denizd.substitutionplan.models.Subst @@ -28,7 +28,7 @@ internal class PersonalPlanFragment : PlanFragment() { recyclerView.visibility = View.VISIBLE substitutions.filter { substitution -> - MiscData.checkPersonalSubstitutions( + HelperFunctions.checkPersonalSubstitutions( substitution, coursePreference, classPreference, diff --git a/app/src/main/java/com/denizd/substitutionplan/fragments/SettingsFragment.kt b/app/src/main/java/com/denizd/substitutionplan/fragments/SettingsFragment.kt index f49bd54..69c83f3 100644 --- a/app/src/main/java/com/denizd/substitutionplan/fragments/SettingsFragment.kt +++ b/app/src/main/java/com/denizd/substitutionplan/fragments/SettingsFragment.kt @@ -27,7 +27,7 @@ import androidx.recyclerview.widget.RecyclerView import com.denizd.substitutionplan.* import com.denizd.substitutionplan.adapters.ColourAdapter import com.denizd.substitutionplan.adapters.RingtoneAdapter -import com.denizd.substitutionplan.data.MiscData +import com.denizd.substitutionplan.data.HelperFunctions import com.denizd.substitutionplan.models.Colour import com.denizd.substitutionplan.models.Ringtone import com.google.android.material.bottomnavigation.BottomNavigationView @@ -116,7 +116,7 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl override fun afterTextChanged(s: Editable) {} override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { - edit.putString("username", txtName.text.toString()).apply() + edit.putString("username", txtName.text.toString().trim()).apply() } }) @@ -255,9 +255,9 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl R.id.switchNotifications -> { edit.putBoolean("notif", isChecked) if (isChecked) { - FirebaseMessaging.getInstance().subscribeToTopic("substitutions-android") + subToTopic("android") } else { - FirebaseMessaging.getInstance().unsubscribeFromTopic("substitutions-android") + unsubFromTopic("android") } } R.id.switchDefaultPlan -> { @@ -290,11 +290,11 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl val titleText = dialogView.findViewById(R.id.empty_textviewtitle) titleText.text = getString(R.string.customiseColoursTitle) colourRecycler = dialogView.findViewById(R.id.recyclerView) - colourRecycler.hasFixedSize() - - colourRecycler.layoutManager = GridLayoutManager(mContext, 1) - colourRecycler.adapter = ColourAdapter(getColourList(), this) - + colourRecycler.apply { + hasFixedSize() + layoutManager = GridLayoutManager(mContext, 1) + adapter = ColourAdapter(getColourList(), this@SettingsFragment) + } colourCustomiserBuilder.setView(dialogView) val colourCustomiserDialog = colourCustomiserBuilder.create() colourCustomiserDialog.show() @@ -302,7 +302,7 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl private fun getColourList(): ArrayList { val colours = ArrayList() - val coursesNoLang = MiscData.languageIndependentCourses + val coursesNoLang = HelperFunctions.languageIndependentCourses val courses = arrayOf(getString(R.string.courseDeu), getString( R.string.courseEng ), getString(R.string.courseFra), getString(R.string.courseSpa), getString( @@ -335,7 +335,7 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl courses[i], coursesNoLang[i], coursesIcons[i], - MiscData.getColourForString(prefs.getString("card${coursesNoLang[i]}", "") ?: "") + HelperFunctions.getColourForString(prefs.getString("card${coursesNoLang[i]}", "") ?: "") ) ) } @@ -344,7 +344,7 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl private fun createRingtoneDialog() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - MiscData.getNotificationChannel(mContext, prefs) + HelperFunctions.getNotificationChannel(mContext, prefs) val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply { putExtra(Settings.EXTRA_APP_PACKAGE, mContext.applicationContext.packageName) putExtra(Settings.EXTRA_CHANNEL_ID, "general") @@ -431,7 +431,7 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl R.id.teal, R.id.cyan, R.id.blue, R.id.purple, R.id.pink, R.id.brown, R.id.grey, R.id.pureWhite, R.id.salmon, R.id.tangerine, R.id.banana, R.id.flora, R.id.spindrift, R.id.sky, R.id.orchid, R.id.lavender, R.id.carnation, R.id.brown2, R.id.pureBlack) - val colours = MiscData.colourNames + val colours = HelperFunctions.colourNames for (i2 in 0 until buttons.size) { picker.findViewById(buttons[i2]).setOnClickListener { @@ -516,8 +516,10 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl } "_DEVCHANNEL" -> { val subbed = if (prefs.getBoolean("subscribedToFBDebugChannel", false)) { + unsubFromTopic("debug") "Unsubscribed from" } else { + subToTopic("debug") "Subscribed to" } edit.putBoolean("subscribedToFBDebugChannel", !prefs.getBoolean("subscribedToFBDebugChannel", false)).apply() @@ -525,13 +527,17 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl } "_IOSCHANNEL" -> { val subbed = if (prefs.getBoolean("subscribedToiOSChannel", false)) { + unsubFromTopic("ios") "Unsubscribed from" } else { + subToTopic("ios") "Subscribed to" } edit.putBoolean("subscribedToiOSChannel", !prefs.getBoolean("subscribedToiOSChannel", false)).apply() makeToast("$subbed iOS channel") } + "_WRITE" -> HelperFunctions.writePrefsToXml(prefs, mContext, activity!!) + "_READ" -> HelperFunctions.readPrefsFromXml(prefs, mContext, activity!!) else -> makeToast(getString(R.string.invalidCode)) } } @@ -554,4 +560,7 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl "\n\nSubscribed to notification channel: ${prefs.getBoolean("notif", false)}" + "\n\nSubscribed to dev channel: ${prefs.getBoolean("subscribedToFBDebugChannel", false)}" } + + private fun subToTopic(topic: String) = FirebaseMessaging.getInstance().subscribeToTopic("substitutions-$topic") + private fun unsubFromTopic(topic: String) = FirebaseMessaging.getInstance().unsubscribeFromTopic("substitutions-$topic") } \ No newline at end of file diff --git a/app/src/main/java/com/denizd/substitutionplan/models/Colour.kt b/app/src/main/java/com/denizd/substitutionplan/models/Colour.kt index aab34fb..e05a7fa 100644 --- a/app/src/main/java/com/denizd/substitutionplan/models/Colour.kt +++ b/app/src/main/java/com/denizd/substitutionplan/models/Colour.kt @@ -1,3 +1,3 @@ package com.denizd.substitutionplan.models -internal class Colour(val title: String, val titleNoLang: String, val icon: Int, val colour: Int) \ No newline at end of file +internal data class Colour(val title: String, val titleNoLang: String, val icon: Int, val colour: Int) \ No newline at end of file diff --git a/app/src/main/java/com/denizd/substitutionplan/models/Food.kt b/app/src/main/java/com/denizd/substitutionplan/models/Food.kt index 38908bd..fb7a79f 100644 --- a/app/src/main/java/com/denizd/substitutionplan/models/Food.kt +++ b/app/src/main/java/com/denizd/substitutionplan/models/Food.kt @@ -4,4 +4,4 @@ import androidx.room.Entity import androidx.room.PrimaryKey @Entity(tableName = "food_table") -internal class Food(val food: String, @PrimaryKey val priority: Int) +internal data class Food(val food: String, @PrimaryKey val priority: Int) diff --git a/app/src/main/java/com/denizd/substitutionplan/models/Ringtone.kt b/app/src/main/java/com/denizd/substitutionplan/models/Ringtone.kt index 462763c..47c7cdb 100644 --- a/app/src/main/java/com/denizd/substitutionplan/models/Ringtone.kt +++ b/app/src/main/java/com/denizd/substitutionplan/models/Ringtone.kt @@ -1,3 +1,3 @@ package com.denizd.substitutionplan.models -internal class Ringtone(val name: String, val uri: String) \ No newline at end of file +internal data class Ringtone(val name: String, val uri: String) \ No newline at end of file diff --git a/app/src/main/java/com/denizd/substitutionplan/models/Subst.kt b/app/src/main/java/com/denizd/substitutionplan/models/Subst.kt index 805bda2..9db7c68 100644 --- a/app/src/main/java/com/denizd/substitutionplan/models/Subst.kt +++ b/app/src/main/java/com/denizd/substitutionplan/models/Subst.kt @@ -4,7 +4,7 @@ import androidx.room.Entity import androidx.room.PrimaryKey @Entity(tableName = "subst_table") -internal class Subst(val group: String, val date: String, val time: String, val course: String, val room: String, val additional: String, val priority: Int) { +internal data class Subst(val group: String, val date: String, val time: String, val course: String, val room: String, val additional: String, val priority: Int) { @PrimaryKey(autoGenerate = true) var id: Int = 0 diff --git a/app/src/main/res/layout/activity_first_time.xml b/app/src/main/res/layout/activity_first_time.xml index 3ce7273..98ccc67 100644 --- a/app/src/main/res/layout/activity_first_time.xml +++ b/app/src/main/res/layout/activity_first_time.xml @@ -160,9 +160,9 @@ android:id="@+id/txtSenior" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="16dp" android:text="@string/seniorCourses" android:gravity="start" + android:layout_marginTop="16dp" android:textColor="@color/colorText" app:layout_constraintEnd_toEndOf="@+id/txtLayoutClasses" app:layout_constraintStart_toStartOf="@+id/txtLayoutClasses" @@ -274,6 +274,33 @@ app:layout_constraintStart_toStartOf="@+id/txtLayoutClasses" app:layout_constraintTop_toBottomOf="@+id/cbNotif" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 25f74e6..bd787e1 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -134,4 +134,8 @@ Keine Klingeltöne gefunden Öffnet Geräteinstellungen Standard + Bitte erlaube Speicherzugriff + Erfolg + von Datei wiederherstellen + du kannst auch… \ 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 555f4df..4cdf5df 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -148,4 +148,8 @@ No ringtones found Redirects to device settings Default + Please enable storage permissions + Success + Restore from file + you may also…