add ability to reorder logins #48
@@ -359,55 +359,87 @@ class SettingsLoginsFragment : Fragment() {
|
|||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class LoginEntry(val logoRes: Int, val displayName: String, val onClick: () -> Unit)
|
||||||
|
|
||||||
private fun buildLoginsSection() {
|
private fun buildLoginsSection() {
|
||||||
val ctx = requireContext()
|
val ctx = requireContext()
|
||||||
val store = CredentialStore(ctx)
|
val store = CredentialStore(ctx)
|
||||||
val container = binding.loginsContainer
|
val container = binding.loginsContainer
|
||||||
container.removeAllViews()
|
container.removeAllViews()
|
||||||
|
|
||||||
val mibLoginIds = store.getMibLoginIds()
|
var anyLogins = false
|
||||||
val bmlLoginIds = store.getBmlLoginIds()
|
|
||||||
val fahipayLoginIds = store.getFahipayLoginIds()
|
|
||||||
val mfaisaLoginIds = store.getMfaisaLoginIds()
|
|
||||||
|
|
||||||
binding.tvLoginsTitle.visibility = if (mibLoginIds.isNotEmpty() || bmlLoginIds.isNotEmpty() || fahipayLoginIds.isNotEmpty() || mfaisaLoginIds.isNotEmpty()) View.VISIBLE else View.GONE
|
fun addGroup(loginIds: List<String>, entryFor: (String) -> LoginEntry, persistOrder: (List<String>) -> Unit) {
|
||||||
|
if (loginIds.isEmpty()) return
|
||||||
|
anyLogins = true
|
||||||
|
val groupContainer = LinearLayout(ctx).apply { orientation = LinearLayout.VERTICAL }
|
||||||
|
loginIds.forEachIndexed { index, loginId ->
|
||||||
|
val entry = entryFor(loginId)
|
||||||
|
fun swapAndPersist(otherIndex: Int) {
|
||||||
|
val newOrder = loginIds.toMutableList().apply {
|
||||||
|
val tmp = this[index]; this[index] = this[otherIndex]; this[otherIndex] = tmp
|
||||||
|
}
|
||||||
|
persistOrder(newOrder)
|
||||||
|
buildLoginsSection()
|
||||||
|
}
|
||||||
|
addLoginRow(
|
||||||
|
groupContainer, entry.logoRes, entry.displayName, entry.onClick,
|
||||||
|
canMoveUp = index > 0,
|
||||||
|
canMoveDown = index < loginIds.size - 1,
|
||||||
|
onMoveUp = { swapAndPersist(index - 1) },
|
||||||
|
onMoveDown = { swapAndPersist(index + 1) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
container.addView(groupContainer)
|
||||||
|
}
|
||||||
|
|
||||||
for (loginId in mibLoginIds) {
|
addGroup(store.getMibLoginIds(), { loginId ->
|
||||||
val profile = store.loadMibUserProfile(loginId)
|
val profile = store.loadMibUserProfile(loginId)
|
||||||
val displayName = profile?.fullName?.takeIf { it.isNotBlank() } ?: getString(R.string.mib_name)
|
val displayName = profile?.fullName?.takeIf { it.isNotBlank() } ?: getString(R.string.mib_name)
|
||||||
val mibProfiles = store.loadMibProfiles(loginId)
|
val mibProfiles = store.loadMibProfiles(loginId)
|
||||||
addLoginRow(container, R.drawable.mib_logo, displayName) {
|
LoginEntry(R.drawable.mib_logo, displayName) {
|
||||||
showMibLoginDetails(store, loginId, profile, mibProfiles)
|
showMibLoginDetails(store, loginId, profile, mibProfiles)
|
||||||
}
|
}
|
||||||
}
|
}, store::setMibLoginIds)
|
||||||
|
|
||||||
for (loginId in bmlLoginIds) {
|
addGroup(store.getBmlLoginIds(), { loginId ->
|
||||||
val profile = store.loadBmlUserProfile(loginId)
|
val profile = store.loadBmlUserProfile(loginId)
|
||||||
val displayName = profile?.fullName?.takeIf { it.isNotBlank() } ?: getString(R.string.bml_name)
|
val displayName = profile?.fullName?.takeIf { it.isNotBlank() } ?: getString(R.string.bml_name)
|
||||||
val bmlProfiles = store.loadBmlProfiles(loginId)
|
val bmlProfiles = store.loadBmlProfiles(loginId)
|
||||||
addLoginRow(container, R.drawable.bml_logo_vector, displayName) {
|
LoginEntry(R.drawable.bml_logo_vector, displayName) {
|
||||||
showBmlLoginDetails(store, loginId, profile, bmlProfiles)
|
showBmlLoginDetails(store, loginId, profile, bmlProfiles)
|
||||||
}
|
}
|
||||||
}
|
}, store::setBmlLoginIds)
|
||||||
|
|
||||||
for (loginId in fahipayLoginIds) {
|
addGroup(store.getFahipayLoginIds(), { loginId ->
|
||||||
val profile = store.loadFahipayUserProfile(loginId)
|
val profile = store.loadFahipayUserProfile(loginId)
|
||||||
val displayName = profile?.fullName?.takeIf { it.isNotBlank() } ?: getString(R.string.fahipay_name)
|
val displayName = profile?.fullName?.takeIf { it.isNotBlank() } ?: getString(R.string.fahipay_name)
|
||||||
addLoginRow(container, R.drawable.fahipay_logo, displayName) {
|
LoginEntry(R.drawable.fahipay_logo, displayName) {
|
||||||
showFahipayLoginDetails(store, loginId, profile)
|
showFahipayLoginDetails(store, loginId, profile)
|
||||||
}
|
}
|
||||||
}
|
}, store::setFahipayLoginIds)
|
||||||
|
|
||||||
for (loginId in mfaisaLoginIds) {
|
addGroup(store.getMfaisaLoginIds(), { loginId ->
|
||||||
val profile = store.loadMfaisaUserProfile(loginId)
|
val profile = store.loadMfaisaUserProfile(loginId)
|
||||||
val displayName = profile?.name?.takeIf { it.isNotBlank() } ?: getString(R.string.ooredoo_name)
|
val displayName = profile?.name?.takeIf { it.isNotBlank() } ?: getString(R.string.ooredoo_name)
|
||||||
addLoginRow(container, R.drawable.ooredoo_logo, displayName) {
|
LoginEntry(R.drawable.ooredoo_logo, displayName) {
|
||||||
showMfaisaLoginDetails(store, loginId, profile)
|
showMfaisaLoginDetails(store, loginId, profile)
|
||||||
}
|
}
|
||||||
}
|
}, store::setMfaisaLoginIds)
|
||||||
|
|
||||||
|
binding.tvLoginsTitle.visibility = if (anyLogins) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addLoginRow(container: LinearLayout, logoRes: Int, displayName: String, onClick: () -> Unit) {
|
private fun addLoginRow(
|
||||||
|
container: LinearLayout,
|
||||||
|
logoRes: Int,
|
||||||
|
displayName: String,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
canMoveUp: Boolean,
|
||||||
|
canMoveDown: Boolean,
|
||||||
|
onMoveUp: () -> Unit,
|
||||||
|
onMoveDown: () -> Unit
|
||||||
|
) {
|
||||||
val ctx = requireContext()
|
val ctx = requireContext()
|
||||||
val dp = ctx.resources.displayMetrics.density
|
val dp = ctx.resources.displayMetrics.density
|
||||||
val row = LinearLayout(ctx).apply {
|
val row = LinearLayout(ctx).apply {
|
||||||
@@ -429,10 +461,31 @@ class SettingsLoginsFragment : Fragment() {
|
|||||||
setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyLarge)
|
setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyLarge)
|
||||||
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
|
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
|
||||||
}
|
}
|
||||||
row.addView(logo); row.addView(tvName)
|
val btnUp = makeMoveButton(ctx, rotationDeg = -90f, enabled = canMoveUp, onClick = onMoveUp)
|
||||||
|
val btnDown = makeMoveButton(ctx, rotationDeg = 90f, enabled = canMoveDown, onClick = onMoveDown)
|
||||||
|
row.addView(logo); row.addView(tvName); row.addView(btnUp); row.addView(btnDown)
|
||||||
container.addView(row)
|
container.addView(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun makeMoveButton(ctx: Context, rotationDeg: Float, enabled: Boolean, onClick: () -> Unit): ImageView {
|
||||||
|
val dp = ctx.resources.displayMetrics.density
|
||||||
|
val size = (32 * dp).toInt()
|
||||||
|
return ImageView(ctx).apply {
|
||||||
|
setImageResource(R.drawable.ic_arrow_right)
|
||||||
|
rotation = rotationDeg
|
||||||
|
scaleType = ImageView.ScaleType.CENTER_INSIDE
|
||||||
|
val ta = ctx.obtainStyledAttributes(intArrayOf(android.R.attr.selectableItemBackgroundBorderless))
|
||||||
|
background = ta.getDrawable(0); ta.recycle()
|
||||||
|
val iconColor = com.google.android.material.color.MaterialColors.getColor(
|
||||||
|
ctx, com.google.android.material.R.attr.colorOnSurfaceVariant, android.graphics.Color.GRAY)
|
||||||
|
imageTintList = android.content.res.ColorStateList.valueOf(iconColor)
|
||||||
|
alpha = if (enabled) 1f else 0.3f
|
||||||
|
isClickable = enabled; isFocusable = enabled
|
||||||
|
layoutParams = LinearLayout.LayoutParams(size, size).apply { marginStart = (4 * dp).toInt() }
|
||||||
|
if (enabled) setOnClickListener { onClick() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun showMibLoginDetails(
|
private fun showMibLoginDetails(
|
||||||
store: CredentialStore,
|
store: CredentialStore,
|
||||||
loginId: String,
|
loginId: String,
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ class CredentialStore(context: Context) {
|
|||||||
|
|
||||||
fun hasMibCredentials(): Boolean = getMibLoginIds().isNotEmpty()
|
fun hasMibCredentials(): Boolean = getMibLoginIds().isNotEmpty()
|
||||||
|
|
||||||
|
fun setMibLoginIds(order: List<String>) {
|
||||||
|
if (order.toSet() != getMibLoginIds().toSet()) return
|
||||||
|
prefs.edit().putString("mib_login_ids", org.json.JSONArray(order).toString()).apply()
|
||||||
|
}
|
||||||
|
|
||||||
private fun addMibLoginId(loginId: String) {
|
private fun addMibLoginId(loginId: String) {
|
||||||
val ids = getMibLoginIds().toMutableList()
|
val ids = getMibLoginIds().toMutableList()
|
||||||
if (loginId !in ids) {
|
if (loginId !in ids) {
|
||||||
@@ -160,6 +165,11 @@ class CredentialStore(context: Context) {
|
|||||||
|
|
||||||
fun hasBmlCredentials(): Boolean = getBmlLoginIds().isNotEmpty()
|
fun hasBmlCredentials(): Boolean = getBmlLoginIds().isNotEmpty()
|
||||||
|
|
||||||
|
fun setBmlLoginIds(order: List<String>) {
|
||||||
|
if (order.toSet() != getBmlLoginIds().toSet()) return
|
||||||
|
prefs.edit().putString("bml_login_ids", org.json.JSONArray(order).toString()).apply()
|
||||||
|
}
|
||||||
|
|
||||||
private fun addBmlLoginId(loginId: String) {
|
private fun addBmlLoginId(loginId: String) {
|
||||||
val ids = getBmlLoginIds().toMutableList()
|
val ids = getBmlLoginIds().toMutableList()
|
||||||
if (loginId !in ids) {
|
if (loginId !in ids) {
|
||||||
@@ -316,6 +326,11 @@ class CredentialStore(context: Context) {
|
|||||||
|
|
||||||
fun hasFahipayCredentials(): Boolean = getFahipayLoginIds().isNotEmpty()
|
fun hasFahipayCredentials(): Boolean = getFahipayLoginIds().isNotEmpty()
|
||||||
|
|
||||||
|
fun setFahipayLoginIds(order: List<String>) {
|
||||||
|
if (order.toSet() != getFahipayLoginIds().toSet()) return
|
||||||
|
prefs.edit().putString("fahipay_login_ids", org.json.JSONArray(order).toString()).apply()
|
||||||
|
}
|
||||||
|
|
||||||
private fun addFahipayLoginId(loginId: String) {
|
private fun addFahipayLoginId(loginId: String) {
|
||||||
val ids = getFahipayLoginIds().toMutableList()
|
val ids = getFahipayLoginIds().toMutableList()
|
||||||
if (loginId !in ids) {
|
if (loginId !in ids) {
|
||||||
@@ -473,6 +488,11 @@ class CredentialStore(context: Context) {
|
|||||||
|
|
||||||
fun hasMfaisaCredentials(): Boolean = getMfaisaLoginIds().isNotEmpty()
|
fun hasMfaisaCredentials(): Boolean = getMfaisaLoginIds().isNotEmpty()
|
||||||
|
|
||||||
|
fun setMfaisaLoginIds(order: List<String>) {
|
||||||
|
if (order.toSet() != getMfaisaLoginIds().toSet()) return
|
||||||
|
prefs.edit().putString("mfaisa_login_ids", org.json.JSONArray(order).toString()).apply()
|
||||||
|
}
|
||||||
|
|
||||||
private fun addMfaisaLoginId(loginId: String) {
|
private fun addMfaisaLoginId(loginId: String) {
|
||||||
val ids = getMfaisaLoginIds().toMutableList()
|
val ids = getMfaisaLoginIds().toMutableList()
|
||||||
if (loginId !in ids) {
|
if (loginId !in ids) {
|
||||||
|
|||||||
Reference in New Issue
Block a user