Skip to content

Commit

Permalink
Merge pull request #38 from 0x4f53/phone-companion
Browse files Browse the repository at this point in the history
Phone companion
  • Loading branch information
0x4f53 authored Mar 3, 2024
2 parents c2d2b08 + bd41387 commit 564d67d
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 44 deletions.
11 changes: 5 additions & 6 deletions .idea/deploymentTargetDropDown.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ android {
applicationId 'zeroxfourf.wristkey'
minSdk 23 // Wear OS 2.0 / Android 7.1.1
targetSdkVersion 33 // Play Store requires API29+
versionCode 32
versionName "3.0"
versionCode 33
versionName "3.1"

ndk {
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/zeroxfourf/wristkey/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ class MainActivity : AppCompatActivity() {
for (login in data.otpauth) utilities.decodeOtpAuthURL(login)?.let { logins.add(it) }

loginsRecycler = findViewById(R.id.loginsRecycler)
loginsAdapter = LoginsAdapter(logins, timer, isRound)
loginsAdapter = LoginsAdapter(logins, timer, isRound, this@MainActivity)
loginsRecycler.adapter = loginsAdapter

callback = ItemTouchHelperCallback(loginsAdapter, logins)
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/java/zeroxfourf/wristkey/SettingsActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ class SettingsActivity : AppCompatActivity() {
utilities.db.edit().putBoolean(utilities.SCROLLING_TEXT, isChecked).apply()
}

var compactDevice = false
val width = utilities.screenResolution(applicationContext).first
if (width < 640) compactDevice = true

compactButton.isChecked = utilities.db.getBoolean(utilities.SETTINGS_COMPACT_ENABLED, compactDevice)
compactButton.setOnCheckedChangeListener { _, isChecked ->
settingsChanged = true
utilities.db.edit().remove(utilities.SETTINGS_COMPACT_ENABLED).apply()
utilities.db.edit().putBoolean(utilities.SETTINGS_COMPACT_ENABLED, isChecked).apply()
}

aboutButton.setOnClickListener {
startActivity(Intent(applicationContext, AboutActivity::class.java))
}
Expand Down
124 changes: 91 additions & 33 deletions app/src/main/java/zeroxfourf/wristkey/Utilities.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ import dev.turingcomplete.kotlinonetimepassword.HmacOneTimePasswordGenerator
import dev.turingcomplete.kotlinonetimepassword.TimeBasedOneTimePasswordConfig
import dev.turingcomplete.kotlinonetimepassword.TimeBasedOneTimePasswordGenerator
import fi.iki.elonen.NanoHTTPD
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
Expand Down Expand Up @@ -572,6 +576,17 @@ class Utilities (context: Context) {
} catch (_: Exception) { }
}

fun screenResolution(context: Context): Pair<Int, Int> {
val metrics = android.util.DisplayMetrics()
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
windowManager.defaultDisplay.getMetrics(metrics)

val width = metrics.widthPixels
val height = metrics.heightPixels

return Pair(width, height)
}

fun getLocalIpAddress(context: Context): String? {
try {
val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
Expand Down Expand Up @@ -615,6 +630,11 @@ class Utilities (context: Context) {
return TimeBasedOneTimePasswordGenerator(secret.toByteArray(Charset.defaultCharset()), config).generate()
}

private fun pixelsToSp(context: Context, px: Float): Float {
val scaledDensity = context.resources.displayMetrics.scaledDensity
return px / scaledDensity
}

fun generateHotp (secret: String, algorithm: String, digits: Int, counter: Long): String {
lateinit var _algorithm: HmacAlgorithm
when (algorithm) {
Expand Down Expand Up @@ -764,7 +784,7 @@ class ItemTouchHelperCallback(private val adapter: ItemTouchHelperAdapter, val l

}

class LoginsAdapter(private var data: MutableList<Utilities.MfaCode>, val timer: Timer, val isRound: Boolean) : RecyclerView.Adapter<LoginsAdapter.ViewHolder>(), ItemTouchHelperAdapter {
class LoginsAdapter(private var data: MutableList<Utilities.MfaCode>, val timer: Timer, val isRound: Boolean, val activity: Activity) : RecyclerView.Adapter<LoginsAdapter.ViewHolder>(), ItemTouchHelperAdapter {

lateinit var context: Context
lateinit var utilities: Utilities
Expand Down Expand Up @@ -822,47 +842,40 @@ class LoginsAdapter(private var data: MutableList<Utilities.MfaCode>, val timer:

fun bind(item: Utilities.MfaCode) {

code.text = "lmao"
accountAndLabel.isSelected = true

if (!utilities.db.getBoolean(utilities.SCROLLING_TEXT, true)) accountAndLabel.ellipsize = null
var compactDeviceSetting = false
val width = utilities.screenResolution(context).first
if (width < 640) compactDeviceSetting = true
val compactDevice = utilities.db.getBoolean(utilities.SETTINGS_COMPACT_ENABLED, compactDeviceSetting)

accountIcon.text = item.issuer[0].toString()
issuer.text = item.issuer
lateinit var mfaCode: String

var assembledLabel = item.account
if (item.label.isNotBlank()) assembledLabel = "$assembledLabel (${item.label})"
if (item.account.isNotBlank()) accountAndLabel.text = assembledLabel else accountAndLabel.visibility = View.GONE
if (compactDevice) {
code.visibility = View.VISIBLE

// Time mode
if (item.mode.contains(utilities.MFA_TIME_MODE)) {
counterControls.visibility = View.GONE
code.visibility = View.GONE
issuer.textSize = 20f
accountAndLabel.textSize = 16f

loginInfo.setOnClickListener {
code.visibility = View.VISIBLE

var mfaCode = utilities.generateTotp(
secret = item.secret,
algorithm = item.algorithm,
digits = item.digits,
period = item.period
)
mfaCode = utilities.generateTotp(secret=item.secret, algorithm=item.algorithm, digits=item.digits, period=item.period)
mfaCode = "${mfaCode.substring(0, mfaCode.length / 2)} ${mfaCode.substring(mfaCode.length / 2)}"

mfaCode = "${mfaCode.substring(0, mfaCode.length / 2)} ${mfaCode.substring(mfaCode.length / 2)}"
code.text = mfaCode
code.text = mfaCode

clipboard.setPrimaryClip(ClipData.newPlainText(context.getString(R.string.app_name), mfaCode.replace(" ", "")))
loginInfo.setOnClickListener { clipboard.setPrimaryClip(ClipData.newPlainText(context.getString(R.string.app_name), mfaCode.replace(" ", ""))) }

code.post {
val cx: Int = code.width / 2
val cy: Int = code.height / 2
val finalRadius = hypot(cx.toDouble(), cy.toDouble()).toFloat()
val anim = ViewAnimationUtils.createCircularReveal(code, cx, cy, 0f, finalRadius)
issuer.visibility = View.GONE
accountAndLabel.visibility = View.GONE
code.visibility = View.VISIBLE
anim.start()
}
} else {

code.visibility = View.GONE

mfaCode = utilities.generateTotp(secret=item.secret, algorithm=item.algorithm, digits=item.digits, period=item.period)
mfaCode = "${mfaCode.substring(0, mfaCode.length / 2)} ${mfaCode.substring(mfaCode.length / 2)}"

code.text = mfaCode

loginInfo.setOnClickListener {
clipboard.setPrimaryClip(ClipData.newPlainText(context.getString(R.string.app_name), mfaCode.replace(" ", "")))

Handler().postDelayed({
code.post {
Expand All @@ -882,8 +895,37 @@ class LoginsAdapter(private var data: MutableList<Utilities.MfaCode>, val timer:
anim.start()
}
}, 3000)

code.post {
val cx: Int = code.width / 2
val cy: Int = code.height / 2
val finalRadius = hypot(cx.toDouble(), cy.toDouble()).toFloat()
val anim = ViewAnimationUtils.createCircularReveal(code, cx, cy, 0f, finalRadius)
issuer.visibility = View.GONE
accountAndLabel.visibility = View.GONE
code.visibility = View.VISIBLE
anim.start()
}


}

}

accountAndLabel.isSelected = true
if (!utilities.db.getBoolean(utilities.SCROLLING_TEXT, true)) accountAndLabel.ellipsize = null

accountIcon.text = item.issuer[0].toString()
issuer.text = item.issuer

var assembledLabel = item.account
if (item.label.isNotBlank()) assembledLabel = "$assembledLabel (${item.label})"
if (item.account.isNotBlank()) accountAndLabel.text = assembledLabel else accountAndLabel.visibility = View.GONE

// Time mode
if (item.mode.contains(utilities.MFA_TIME_MODE)) {
counterControls.visibility = View.GONE

progressIndicator.max = item.period

if (isRound) {
Expand All @@ -897,10 +939,24 @@ class LoginsAdapter(private var data: MutableList<Utilities.MfaCode>, val timer:
override fun run() {
val second = utilities.second()
val tickerValue = (item.period - (second % item.period)) % item.period

try {
progressIndicator.progress = tickerValue
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) progressIndicator.setProgress(tickerValue, true)
} catch (_: Exception) { }

if (tickerValue == 29) {

CoroutineScope(Dispatchers.IO).launch {
mfaCode = utilities.generateTotp(secret=item.secret, algorithm=item.algorithm, digits=item.digits, period=item.period)
mfaCode = "${mfaCode.substring(0, mfaCode.length / 2)} ${mfaCode.substring(mfaCode.length / 2)}"
withContext(Dispatchers.Main) {
code.text = mfaCode
}
}

}

}
}, 0, 1000)
}
Expand Down Expand Up @@ -972,6 +1028,8 @@ class LoginsAdapter(private var data: MutableList<Utilities.MfaCode>, val timer:

}

code.visibility = View.VISIBLE

}

}
Expand Down
3 changes: 1 addition & 2 deletions app/src/main/res/layout/activity_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,7 @@
android:background="@drawable/pill_shape_border"
android:orientation="horizontal"
android:paddingStart="15dp"
android:paddingEnd="10dp"
android:visibility="gone">
android:paddingEnd="10dp">

<TextView
android:id="@+id/compactText"
Expand Down
Binary file added screenshots/phonehome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/phonesearch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/phonesend.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/phonesettings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 564d67d

Please sign in to comment.