Added individual service toggle and priority switch
This commit is contained in:
parent
707cd39ef8
commit
b09b6578bb
13 changed files with 328 additions and 83 deletions
|
@ -17,20 +17,19 @@ class CallRedirectionService : CallRedirectionService() {
|
|||
private const val TELEGRAM_MIMETYPE = "$PREFIX/vnd.org.telegram.messenger.android.call"
|
||||
private const val THREEMA_MIMETYPE = "$PREFIX/vnd.ch.threema.app.call"
|
||||
private const val WHATSAPP_MIMETYPE = "$PREFIX/vnd.com.whatsapp.voip.call"
|
||||
private val MIMETYPE_TO_WEIGHT = mapOf(
|
||||
SIGNAL_MIMETYPE to 0,
|
||||
TELEGRAM_MIMETYPE to 1,
|
||||
THREEMA_MIMETYPE to 2,
|
||||
WHATSAPP_MIMETYPE to 48,
|
||||
)
|
||||
private val FALLBACK_MIMETYPES = arrayOf(
|
||||
|
||||
val ALL_MIMETYPES = arrayOf(
|
||||
SIGNAL_MIMETYPE,
|
||||
TELEGRAM_MIMETYPE,
|
||||
THREEMA_MIMETYPE,
|
||||
WHATSAPP_MIMETYPE,
|
||||
)
|
||||
|
||||
private val MIMETYPE_TO_DST_NAME = mapOf(
|
||||
SIGNAL_MIMETYPE to R.string.destination_signal,
|
||||
TELEGRAM_MIMETYPE to R.string.destination_telegram,
|
||||
THREEMA_MIMETYPE to R.string.destination_threema,
|
||||
WHATSAPP_MIMETYPE to R.string.fallback_destination_whatsapp,
|
||||
WHATSAPP_MIMETYPE to R.string.destination_whatsapp,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -63,6 +62,7 @@ class CallRedirectionService : CallRedirectionService() {
|
|||
placeCallUnmodified()
|
||||
return
|
||||
}
|
||||
|
||||
val records: Array<Record>
|
||||
try {
|
||||
records = getRecordsFromPhoneNumber(handle.schemeSpecificPart)
|
||||
|
@ -70,11 +70,18 @@ class CallRedirectionService : CallRedirectionService() {
|
|||
placeCallUnmodified()
|
||||
return
|
||||
}
|
||||
val record = records.minByOrNull { MIMETYPE_TO_WEIGHT[it.mimetype] ?: 0 }
|
||||
if (record == null || (record.mimetype in FALLBACK_MIMETYPES && !prefs.isFallbackChecked)) {
|
||||
|
||||
// Filter to enabled services only
|
||||
val enabledRecords = records
|
||||
.filter { prefs.isServiceEnabled(it.mimetype) }
|
||||
.sortedBy { prefs.getServicePriority(it.mimetype) }
|
||||
|
||||
val record = enabledRecords.firstOrNull()
|
||||
if (record == null) {
|
||||
placeCallUnmodified()
|
||||
return
|
||||
}
|
||||
|
||||
window.show(record.uri, MIMETYPE_TO_DST_NAME[record.mimetype] ?: return)
|
||||
}
|
||||
|
||||
|
@ -109,9 +116,8 @@ class CallRedirectionService : CallRedirectionService() {
|
|||
ContactsContract.Data.CONTENT_URI,
|
||||
arrayOf(ContactsContract.Data._ID, ContactsContract.Data.MIMETYPE),
|
||||
"${ContactsContract.Data.CONTACT_ID} = ? AND " +
|
||||
"${ContactsContract.Data.MIMETYPE} IN " +
|
||||
"(${MIMETYPE_TO_WEIGHT.keys.joinToString(",") { "?" }})",
|
||||
arrayOf(contactId, *MIMETYPE_TO_WEIGHT.keys.toTypedArray()),
|
||||
"${ContactsContract.Data.MIMETYPE} IN (${ALL_MIMETYPES.joinToString(",") { "?" }})",
|
||||
arrayOf(contactId, *ALL_MIMETYPES),
|
||||
null,
|
||||
)
|
||||
cursor?.apply {
|
||||
|
|
|
@ -10,7 +10,17 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import java.lang.NumberFormatException
|
||||
|
||||
import android.text.InputType
|
||||
import android.widget.CheckBox
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import partisan.weforge.xyz.pulse.getServicePriority
|
||||
import partisan.weforge.xyz.pulse.setServicePriority
|
||||
import partisan.weforge.xyz.pulse.isServiceEnabled
|
||||
import partisan.weforge.xyz.pulse.setServiceEnabled
|
||||
import partisan.weforge.xyz.pulse.databinding.ActivityMainBinding
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
@ -55,7 +65,6 @@ class MainActivity : AppCompatActivity() {
|
|||
binding.apply {
|
||||
redirectionDelay.value = (prefs.redirectionDelay / 1000).toFloat()
|
||||
popupPosition.editText?.setText(prefs.popupPosition.toString())
|
||||
fallback.isChecked = prefs.isFallbackChecked
|
||||
toggle.isChecked = prefs.isEnabled
|
||||
}
|
||||
}
|
||||
|
@ -76,9 +85,6 @@ class MainActivity : AppCompatActivity() {
|
|||
prefs.popupPosition = it?.toString()?.toInt() ?: return@doAfterTextChanged
|
||||
} catch (exc: NumberFormatException) {}
|
||||
}
|
||||
fallback.setOnCheckedChangeListener { _, isChecked ->
|
||||
prefs.isFallbackChecked = isChecked
|
||||
}
|
||||
toggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked && !hasPermissions()) {
|
||||
toggle.isChecked = false
|
||||
|
@ -87,6 +93,64 @@ class MainActivity : AppCompatActivity() {
|
|||
}
|
||||
prefs.isEnabled = isChecked
|
||||
}
|
||||
val services = listOf(
|
||||
ServiceEntry("vnd.android.cursor.item/vnd.org.thoughtcrime.securesms.call", R.string.destination_signal, this@MainActivity.isServiceEnabled("vnd.android.cursor.item/vnd.org.thoughtcrime.securesms.call")),
|
||||
ServiceEntry("vnd.android.cursor.item/vnd.org.telegram.messenger.android.call", R.string.destination_telegram, this@MainActivity.isServiceEnabled("vnd.android.cursor.item/vnd.org.telegram.messenger.android.call")),
|
||||
ServiceEntry("vnd.android.cursor.item/vnd.ch.threema.app.call", R.string.destination_threema, this@MainActivity.isServiceEnabled("vnd.android.cursor.item/vnd.ch.threema.app.call")),
|
||||
ServiceEntry("vnd.android.cursor.item/vnd.com.whatsapp.voip.call", R.string.destination_whatsapp, this@MainActivity.isServiceEnabled("vnd.android.cursor.item/vnd.com.whatsapp.voip.call")),
|
||||
)
|
||||
|
||||
val adapter = ServiceAdapter(
|
||||
context = this@MainActivity,
|
||||
services = services.toMutableList(),
|
||||
onReordered = { updatedList ->
|
||||
updatedList.forEachIndexed { index, entry ->
|
||||
setServicePriority(entry.mimetype, index)
|
||||
}
|
||||
}
|
||||
)
|
||||
binding.serviceRecycler.adapter = adapter
|
||||
binding.serviceRecycler.layoutManager = LinearLayoutManager(this@MainActivity)
|
||||
|
||||
val touchHelper = ItemTouchHelper(adapter.dragHelper)
|
||||
touchHelper.attachToRecyclerView(binding.serviceRecycler)
|
||||
|
||||
adapter.setDragStartListener { viewHolder ->
|
||||
touchHelper.startDrag(viewHolder)
|
||||
}
|
||||
|
||||
// binding.serviceConfigList.removeAllViews()
|
||||
// for ((mimetype, labelRes) in mimetypes) {
|
||||
// val checkbox = CheckBox(this@MainActivity).apply {
|
||||
// text = getString(labelRes)
|
||||
// isChecked = this@MainActivity.isServiceEnabled(mimetype)
|
||||
// setOnCheckedChangeListener { _, checked ->
|
||||
// this@MainActivity.setServiceEnabled(mimetype, checked)
|
||||
// }
|
||||
// }
|
||||
|
||||
// val priorityInput = EditText(this@MainActivity).apply {
|
||||
// inputType = InputType.TYPE_CLASS_NUMBER
|
||||
// setEms(4)
|
||||
// hint = "Priority"
|
||||
// setText(this@MainActivity.getServicePriority(mimetype).toString())
|
||||
// setOnFocusChangeListener { _, hasFocus ->
|
||||
// if (!hasFocus) {
|
||||
// val value = text.toString().toIntOrNull()
|
||||
// if (value != null) this@MainActivity.setServicePriority(mimetype, value)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// val row = LinearLayout(this@MainActivity).apply {
|
||||
// orientation = LinearLayout.HORIZONTAL
|
||||
// setPadding(0, 16, 0, 16)
|
||||
// addView(checkbox, LinearLayout.LayoutParams(0, WRAP_CONTENT, 1f))
|
||||
// addView(priorityInput, LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT))
|
||||
// }
|
||||
|
||||
// binding.serviceConfigList.addView(row)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ class PopupWindow(
|
|||
R.string.destination_telegram,
|
||||
R.string.destination_threema,
|
||||
)
|
||||
if (prefs.isFallbackChecked) destinations.add(R.string.fallback_destination_whatsapp)
|
||||
setDescription(destinations.random())
|
||||
add()
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ class Preferences(ctx: Context) {
|
|||
private const val ENABLED = "enabled"
|
||||
private const val REDIRECTION_DELAY = "redirection_delay"
|
||||
private const val POPUP_POSITION = "popup_position_y"
|
||||
private const val FALLBACK_CHECKED = "fallback_checked"
|
||||
|
||||
private const val DEFAULT_REDIRECTION_DELAY = 2000L
|
||||
private const val DEFAULT_POPUP_POSITION = 333
|
||||
|
@ -32,7 +31,26 @@ class Preferences(ctx: Context) {
|
|||
get() = prefs.getInt(POPUP_POSITION, DEFAULT_POPUP_POSITION)
|
||||
set(value) = prefs.edit { putInt(POPUP_POSITION, value) }
|
||||
|
||||
var isFallbackChecked: Boolean
|
||||
get() = prefs.getBoolean(FALLBACK_CHECKED, false)
|
||||
set(value) = prefs.edit { putBoolean(FALLBACK_CHECKED, value) }
|
||||
private fun makeKeyEnabled(mimetype: String) = "enabled_$mimetype"
|
||||
private fun makeKeyPriority(mimetype: String) = "priority_$mimetype"
|
||||
|
||||
/** Whether this service is enabled */
|
||||
fun isServiceEnabled(mimetype: String): Boolean {
|
||||
return prefs.getBoolean(makeKeyEnabled(mimetype), true)
|
||||
}
|
||||
|
||||
/** Current priority for this service (lower = higher priority) */
|
||||
fun getServicePriority(mimetype: String): Int {
|
||||
return prefs.getInt(makeKeyPriority(mimetype), Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
/** Enable or disable individual service */
|
||||
fun setServiceEnabled(mimetype: String, enabled: Boolean) {
|
||||
prefs.edit().putBoolean(makeKeyEnabled(mimetype), enabled).apply()
|
||||
}
|
||||
|
||||
/** Change priority for an individual service */
|
||||
fun setServicePriority(mimetype: String, priority: Int) {
|
||||
prefs.edit().putInt(makeKeyPriority(mimetype), priority).apply()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
package partisan.weforge.xyz.pulse
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.CheckBox
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
class ServiceAdapter(
|
||||
private val context: Context,
|
||||
private val services: MutableList<ServiceEntry>,
|
||||
private val onReordered: (List<ServiceEntry>) -> Unit
|
||||
) : RecyclerView.Adapter<ServiceAdapter.ViewHolder>() {
|
||||
|
||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val label: TextView = view.findViewById(R.id.label)
|
||||
val checkbox: CheckBox = view.findViewById(R.id.checkbox)
|
||||
val handle: ImageView = view.findViewById(R.id.handle)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_service, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val entry = services[position]
|
||||
|
||||
holder.label.setText(entry.labelRes)
|
||||
holder.checkbox.isChecked = entry.enabled
|
||||
|
||||
holder.checkbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
entry.enabled = isChecked
|
||||
context.setServiceEnabled(entry.mimetype, isChecked)
|
||||
}
|
||||
|
||||
holder.handle.setOnTouchListener { _, event ->
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
dragStartListener?.invoke(holder)
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = services.size
|
||||
|
||||
private var dragStartListener: ((RecyclerView.ViewHolder) -> Unit)? = null
|
||||
|
||||
val dragHelper = object : ItemTouchHelper.Callback() {
|
||||
override fun getMovementFlags(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder
|
||||
): Int {
|
||||
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
|
||||
return makeMovementFlags(dragFlags, 0)
|
||||
}
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
val from = viewHolder.adapterPosition
|
||||
val to = target.adapterPosition
|
||||
services.add(to, services.removeAt(from))
|
||||
notifyItemMoved(from, to)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
// No swipe actions
|
||||
}
|
||||
|
||||
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||
super.clearView(recyclerView, viewHolder)
|
||||
onReordered(services)
|
||||
}
|
||||
}
|
||||
|
||||
fun setDragStartListener(listener: (RecyclerView.ViewHolder) -> Unit) {
|
||||
dragStartListener = listener
|
||||
}
|
||||
}
|
33
app/src/main/java/partisan/weforge/xyz/pulse/ServicePrefs.kt
Normal file
33
app/src/main/java/partisan/weforge/xyz/pulse/ServicePrefs.kt
Normal file
|
@ -0,0 +1,33 @@
|
|||
package partisan.weforge.xyz.pulse
|
||||
|
||||
import android.content.Context
|
||||
import androidx.preference.PreferenceManager
|
||||
|
||||
private fun makeKeyEnabled(mimetype: String) = "enabled_$mimetype"
|
||||
private fun makeKeyPriority(mimetype: String) = "priority_$mimetype"
|
||||
|
||||
data class ServiceEntry(
|
||||
val mimetype: String,
|
||||
val labelRes: Int,
|
||||
var enabled: Boolean
|
||||
)
|
||||
|
||||
fun Context.isServiceEnabled(mimetype: String): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
return prefs.getBoolean(makeKeyEnabled(mimetype), true)
|
||||
}
|
||||
|
||||
fun Context.setServiceEnabled(mimetype: String, enabled: Boolean) {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
prefs.edit().putBoolean(makeKeyEnabled(mimetype), enabled).apply()
|
||||
}
|
||||
|
||||
fun Context.getServicePriority(mimetype: String): Int {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
return prefs.getInt(makeKeyPriority(mimetype), Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
fun Context.setServicePriority(mimetype: String, priority: Int) {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
prefs.edit().putInt(makeKeyPriority(mimetype), priority).apply()
|
||||
}
|
9
app/src/main/res/drawable/ic_drag_handle.xml
Normal file
9
app/src/main/res/drawable/ic_drag_handle.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#666"
|
||||
android:pathData="M7,10h2v2H7v-2zm0,-4h2v2H7V6zm0,8h2v2H7v-2zm4,-8h2v2h-2V6zm0,4h2v2h-2v-2zm0,4h2v2h-2v-2z" />
|
||||
</vector>
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
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:layout_width="match_parent"
|
||||
|
@ -12,9 +13,9 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/description"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scrollView"
|
||||
|
@ -22,10 +23,10 @@
|
|||
android:layout_height="0dp"
|
||||
android:padding="16dp"
|
||||
android:layout_marginVertical="16dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/toggle"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/description"
|
||||
app:layout_constraintBottom_toTopOf="@id/toggle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/description">
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -36,65 +37,54 @@
|
|||
android:id="@+id/redirectionDelay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/redirection_delay_description"
|
||||
android:stepSize="0.5"
|
||||
android:valueFrom="2"
|
||||
android:valueTo="4" />
|
||||
android:valueTo="4"
|
||||
android:contentDescription="@string/redirection_delay_description" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description2"
|
||||
android:textSize="12sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/redirection_delay_description" />
|
||||
android:text="@string/redirection_delay_description"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<Space
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="8dp" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/popupPosition"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:endIconMode="custom"
|
||||
app:endIconDrawable="@drawable/ic_baseline_check_circle_24"
|
||||
android:hint="@string/popup_position"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:hint="@string/popup_position">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:inputType="number"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<Space
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="8dp" />
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/fallback"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/serviceRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layoutDirection="rtl"
|
||||
android:text="@string/fallback"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/fallback_description"
|
||||
android:textSize="12sp" />
|
||||
|
||||
android:layout_marginTop="16dp"
|
||||
android:scrollbars="vertical" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
|
@ -105,7 +95,6 @@
|
|||
android:paddingVertical="12dp"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
30
app/src/main/res/layout/item_service.xml
Normal file
30
app/src/main/res/layout/item_service.xml
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/handle"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_drag_handle"
|
||||
android:contentDescription="@null"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingEnd="8dp" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="Label"
|
||||
android:textSize="16sp"
|
||||
android:layout_gravity="center_vertical" />
|
||||
</LinearLayout>
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Pulse</string>
|
||||
<string name="description">L\'application essaiera de rediriger les appels sortants vers Signal/Telegram/Threema s\'ils sont disponibles. Pour fonctionner, l\'application nécessite de nombreuses permissions. Cliquez sur le bouton et accordez les autorisations nécéssaires jusqu\'à ce qu\'il soit activé.</string>
|
||||
<string name="description">L\'application essaiera de rediriger les appels sortants vers Signal/Telegram/Threema/WhatsApp s\'ils sont disponibles. Pour fonctionner, l\'application nécessite de nombreuses permissions. Cliquez sur le bouton et accordez les autorisations nécéssaires jusqu\'à ce qu\'il soit activé.</string>
|
||||
<string name="popup">Redirection vers %1$s</string>
|
||||
<string name="destination_signal">Signal</string>
|
||||
<string name="destination_telegram">Telegram</string>
|
||||
<string name="destination_threema">Threema</string>
|
||||
<string name="redirection_delay_description">Délai avant qu\'un appel ne soit redirigé.</string>
|
||||
<string name="destination_whatsapp">WhatsApp</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Pulse</string>
|
||||
<string name="description">Приложение будет пытаться перенаправить исходящие вызовы в Signal/Telegram/Threema. Для работы ему нужно много разрешений. Кликайте на переключатель и выдавайте разрешения пока он не включится.</string>
|
||||
<string name="description">Приложение будет пытаться перенаправить исходящие вызовы в Signal/Telegram/Threema/WhatsApp. Для работы ему нужно много разрешений. Кликайте на переключатель и выдавайте разрешения пока он не включится.</string>
|
||||
<string name="popup">Перенаправление в %1$s</string>
|
||||
<string name="destination_signal">Signal</string>
|
||||
<string name="destination_telegram">Telegram</string>
|
||||
<string name="destination_threema">Threema</string>
|
||||
<string name="destination_whatsapp">WhatsApp</string>
|
||||
<string name="redirection_delay_description">Задержка до того, как звонок будет перенаправлен.</string>
|
||||
<string name="popup_position">Позиция всплывающего окна</string>
|
||||
<string name="fallback">Обратная совместимость</string>
|
||||
<string name="fallback_description">Перенаправлять в WhatsApp, если другие недоступны.</string>
|
||||
<string name="fallback_destination_whatsapp">WhatsApp</string>
|
||||
</resources>
|
|
@ -1,14 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Pulse</string>
|
||||
<string name="description">The app will try to redirect outgoing calls to Signal/Telegram/Threema if available. For work it requires many permissions. Click on the toggle and grant permissions until it turns ON.</string>
|
||||
<string name="description">The app will try to redirect outgoing calls to Signal/Telegram/Threema/WhatsApp if available. For work it requires many permissions. Click on the toggle and grant permissions until it turns ON.</string>
|
||||
<string name="popup">Redirecting to %1$s</string>
|
||||
<string name="destination_signal">Signal</string>
|
||||
<string name="destination_telegram">Telegram</string>
|
||||
<string name="destination_threema">Threema</string>
|
||||
<string name="destination_whatsapp">WhatsApp</string>
|
||||
<string name="redirection_delay_description">The delay before a call will be redirected.</string>
|
||||
<string name="popup_position">Popup position</string>
|
||||
<string name="fallback">Fallback</string>
|
||||
<string name="fallback_description">Redirect to WhatsApp if no other available.</string>
|
||||
<string name="fallback_destination_whatsapp">WhatsApp</string>
|
||||
</resources>
|
Loading…
Add table
Add a link
Reference in a new issue