From 1a41064b1d1f1dd6c01e0291d90405a6d64b845f Mon Sep 17 00:00:00 2001 From: mariohdel14nasa-lang Date: Sun, 30 Aug 2026 18:25:53 +0200 Subject: [PATCH 1/6] Update README.md --- README.md | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/README.md b/README.md index d37b48b..8b13789 100644 --- a/README.md +++ b/README.md @@ -1,28 +1 @@ -# MeDrop - NameDrop for Android -Share your contact with other easily with NFC or QR code. -

- - - - -

- -

- - -

- -# Join internal testing on Google Play -- First join [this Google group](https://groups.google.com/u/0/g/madebysameerasw). - -- Then, Using the same Google account, You can start testing MeDrop from here: - ### [Android](https://play.google.com/store/apps/details?id=com.sameerasw.medrop) | [Web](https://play.google.com/store/apps/details?id=com.sameerasw.medrop) - -- Done, Download and try it out! - - -

-  reddit-banner -  telegram-banner -

From 57e04e1b7d5ca33f46fcea6445ad52106596dde9 Mon Sep 17 00:00:00 2001 From: mariohdel14nasa-lang Date: Sun, 30 Aug 2026 18:28:33 +0200 Subject: [PATCH 2/6] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 8b13789..4086caf 100644 --- a/README.md +++ b/README.md @@ -1 +1,10 @@ +# Essential Tap +### A contact and file sharing tool forked from sameerasw's MeDrop. +Features: + 路 Data stored on-device + 路 JSON import and export backups + 路 NFC and QR code sharing + 路 Easy to use app + +App: Not done yet 馃槄 From 086fd1dbf21f31a967ae5114b69d69dffe6118d1 Mon Sep 17 00:00:00 2001 From: mariohdel14nasa-lang Date: Sun, 30 Aug 2026 18:30:02 +0200 Subject: [PATCH 3/6] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4086caf..c8fd360 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,5 @@ Features: 路 Easy to use app App: Not done yet 馃槄 + +Feel free to check out the original app! https://github.com/sameerasw/MeDrop From cacaa0b0011ae5124cd71051a430e1afb6fa9222 Mon Sep 17 00:00:00 2001 From: mariohdel14nasa-lang Date: Mon, 31 Aug 2026 20:01:31 +0200 Subject: [PATCH 4/6] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c8fd360..fab0e20 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,6 @@ Features: 路 NFC and QR code sharing 路 Easy to use app -App: Not done yet 馃槄 +App: in the releases tab, then in the "Fixes-for-MeDrop" Feel free to check out the original app! https://github.com/sameerasw/MeDrop From 794a16ec699e74a1f424e36962526b816df11cbd Mon Sep 17 00:00:00 2001 From: mariohdel14nasa-lang Date: Mon, 31 Aug 2026 20:55:54 +0200 Subject: [PATCH 5/6] Added the source code --- .../medrop/domain/model/MeDropContact.kt | 10 +- .../medrop/ui/sheets/MeDropBottomSheet.kt | 16 ++- .../sameerasw/medrop/utils/QrCodeGenerator.kt | 133 ++++++++++-------- 3 files changed, 94 insertions(+), 65 deletions(-) diff --git a/app/src/main/java/com/sameerasw/medrop/domain/model/MeDropContact.kt b/app/src/main/java/com/sameerasw/medrop/domain/model/MeDropContact.kt index 56606d5..6a01b3e 100644 --- a/app/src/main/java/com/sameerasw/medrop/domain/model/MeDropContact.kt +++ b/app/src/main/java/com/sameerasw/medrop/domain/model/MeDropContact.kt @@ -70,7 +70,8 @@ data class MeDropContact( activeEntryIds: Set, customPhotoUri: String? = null, customDisplayName: String? = null, - fieldOverrides: Map = emptyMap() + fieldOverrides: Map = emptyMap(), + includeRev: Boolean = true ): String { val effectiveDisplayName = customDisplayName?.takeIf { it.isNotBlank() } ?: displayName val effectivePhotoUri = customPhotoUri ?: photoUri @@ -110,6 +111,7 @@ data class MeDropContact( (height * ratio).toInt().coerceAtLeast(1), true ) + } else { originalBitmap } @@ -189,8 +191,10 @@ data class MeDropContact( sb.appendLine("NOTE:${effNote.replace("\n", " ")}") } - val rev = SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US).format(Date()) - sb.appendLine("REV:$rev") + if (includeRev) { + val rev = SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US).format(Date()) + sb.appendLine("REV:$rev") + } sb.append("END:VCARD") return sb.toString() } diff --git a/app/src/main/java/com/sameerasw/medrop/ui/sheets/MeDropBottomSheet.kt b/app/src/main/java/com/sameerasw/medrop/ui/sheets/MeDropBottomSheet.kt index a115783..6b8b0a0 100644 --- a/app/src/main/java/com/sameerasw/medrop/ui/sheets/MeDropBottomSheet.kt +++ b/app/src/main/java/com/sameerasw/medrop/ui/sheets/MeDropBottomSheet.kt @@ -251,18 +251,22 @@ fun MeDropBottomSheet( if (isQrModeActive && contact != null) { withContext(Dispatchers.IO) { val profile = safeSettings.getProfile(activeProfileType) + val qrEntryIds = safeSettings.getEffectiveEntryIds(activeProfileType).toMutableSet().apply { + remove("photo") // Photos are too large for QR codes and make the grid too dense + } val vcardString = contact.toVCard( context = context, - activeEntryIds = safeSettings.getEffectiveEntryIds(activeProfileType), + activeEntryIds = qrEntryIds, customPhotoUri = null, customDisplayName = if (activeProfileType != MeDropProfileType.CONTACT) profile.customDisplayName else null, - fieldOverrides = profile.customFieldOverrides + fieldOverrides = profile.customFieldOverrides, + includeRev = false ) val generated = QrCodeGenerator.generateQrBitmap( content = vcardString, - size = 1000, - foregroundColor = AndroidColor.BLACK, - backgroundColor = AndroidColor.WHITE, + size = 1024, + foregroundColor = AndroidColor.WHITE, + backgroundColor = AndroidColor.BLACK, logo = null ) withContext(Dispatchers.Main) { @@ -339,7 +343,7 @@ fun MeDropBottomSheet( val targetPhotoSize = if (isQrModeActive) 80.dp else (200.dp * scanScale) val qrContainerSize by animateDpAsState( - targetValue = if (isQrModeActive) 340.dp else targetPhotoSize, + targetValue = if (isQrModeActive) 380.dp else targetPhotoSize, animationSpec = androidx.compose.animation.core.spring( dampingRatio = androidx.compose.animation.core.Spring.DampingRatioMediumBouncy, stiffness = androidx.compose.animation.core.Spring.StiffnessLow diff --git a/app/src/main/java/com/sameerasw/medrop/utils/QrCodeGenerator.kt b/app/src/main/java/com/sameerasw/medrop/utils/QrCodeGenerator.kt index ec6406a..e88fb1c 100644 --- a/app/src/main/java/com/sameerasw/medrop/utils/QrCodeGenerator.kt +++ b/app/src/main/java/com/sameerasw/medrop/utils/QrCodeGenerator.kt @@ -9,89 +9,110 @@ import android.graphics.RectF import androidx.core.content.ContextCompat import com.google.zxing.BarcodeFormat import com.google.zxing.EncodeHintType +import com.google.zxing.WriterException import com.google.zxing.qrcode.QRCodeWriter import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import com.sameerasw.medrop.R -import java.util.EnumMap import kotlin.math.max +import java.util.HashMap +import java.util.Map + object QrCodeGenerator { fun generateQrBitmap( content: String, - size: Int = 600, - foregroundColor: Int = Color.BLACK, - backgroundColor: Int = Color.WHITE, + size: Int =600, + foregroundColor: Int = Color.WHITE, + backgroundColor: Int = Color.BLACK, logo: Bitmap? = null, - ): Bitmap { - val hints = EnumMap(EncodeHintType::class.java).apply { - put(EncodeHintType.CHARACTER_SET, "UTF-8") - put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H) - put(EncodeHintType.MARGIN, 2) + ): Bitmap? { + // Standard limit for alphanumeric QR codes with low error correction is 4,296 characters + // We use a safe limit of 2,953 to ensure reliability across all QR versions + if (content.trim().isEmpty() || content.length > 2953) { + return null } - val writer = QRCodeWriter() - val bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, size, size, hints) - val moduleCount = bitMatrix.width - val moduleSize = size.toFloat() / moduleCount + try { + val writer = QRCodeWriter() + val hints: MutableMap = HashMap() + hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.L + hints[EncodeHintType.MARGIN] = 0 + val bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, size, size, hints) - val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - canvas.drawColor(backgroundColor) + val moduleCount = bitMatrix.width + val moduleSize = size.toFloat() / moduleCount - val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = foregroundColor - style = Paint.Style.FILL - } + val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + canvas.drawColor(backgroundColor) - val rect = RectF() + val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + color = foregroundColor + style = Paint.Style.FILL_AND_STROKE + strokeWidth = 0.8f + } + + val rect = RectF() - for (y in 0 until moduleCount) { - for (x in 0 until moduleCount) { - if (bitMatrix.get(x, y)) { - val left = x * moduleSize - val top = y * moduleSize - val right = left + moduleSize - val bottom = top + moduleSize - rect.set(left, top, right, bottom) - canvas.drawRect(rect, paint) + for (y in 0 until moduleCount) { + for (x in 0 until moduleCount) { + if (bitMatrix.get(x, y)) { + // We add a tiny 0.5f overlap to ensure squares touch perfectly + // and appear "chunkier" by eliminating anti-aliased gaps. + val left = x * moduleSize + val top = y * moduleSize + val right = (x + 1) * moduleSize + 0.5f + val bottom = (y + 1) * moduleSize + 0.5f + rect.set(left, top, right, bottom) + canvas.drawRect(rect, paint) + } } } - } - if (logo != null) { - val logoSize = size * 0.20f - val logoMargin = (size - logoSize) / 2f - val badgeRect = RectF(logoMargin, logoMargin, logoMargin + logoSize, logoMargin + logoSize) + if (logo != null) { + val logoSize = size * 0.20f + val logoMargin = (size - logoSize) / 2f + val badgeRect = + RectF(logoMargin, logoMargin, logoMargin + logoSize, logoMargin + logoSize) - val badgeBgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = backgroundColor - style = Paint.Style.FILL - } - val badgeStrokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = Color.parseColor("#26000000") - style = Paint.Style.STROKE - strokeWidth = 3f + val badgeBgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + color = backgroundColor + style = Paint.Style.FILL + } + val badgeStrokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + color = Color.parseColor("#26000000") + style = Paint.Style.STROKE + strokeWidth = 3f + } + canvas.drawOval(badgeRect, badgeBgPaint) + canvas.drawOval(badgeRect, badgeStrokePaint) + + val innerPadding = logoSize * 0.14f + val innerRect = RectF( + badgeRect.left + innerPadding, + badgeRect.top + innerPadding, + badgeRect.right - innerPadding, + badgeRect.bottom - innerPadding, + ) + canvas.drawBitmap( + logo, + null, + innerRect, + Paint(Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG) + ) } - canvas.drawOval(badgeRect, badgeBgPaint) - canvas.drawOval(badgeRect, badgeStrokePaint) - val innerPadding = logoSize * 0.14f - val innerRect = RectF( - badgeRect.left + innerPadding, - badgeRect.top + innerPadding, - badgeRect.right - innerPadding, - badgeRect.bottom - innerPadding, - ) - canvas.drawBitmap(logo, null, innerRect, Paint(Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG)) + return bitmap + } catch (e: WriterException) { + return null } - - return bitmap } fun getAppLogoBitmap(context: Context): Bitmap? { return try { - val drawable = ContextCompat.getDrawable(context, R.mipmap.ic_launcher) ?: return null + val drawable = + ContextCompat.getDrawable(context, R.mipmap.ic_launcher) ?: return null val bitmap = Bitmap.createBitmap( max(1, drawable.intrinsicWidth), max(1, drawable.intrinsicHeight), From b587e6d1399612d2f8c6fa8d68b96ab40c544fcb Mon Sep 17 00:00:00 2001 From: mariohdel14nasa-lang Date: Mon, 31 Aug 2026 21:34:41 +0200 Subject: [PATCH 6/6] fixup! Added the source code --- .../medrop/domain/model/MeDropContact.kt | 10 +- .../medrop/ui/sheets/MeDropBottomSheet.kt | 16 +-- .../sameerasw/medrop/utils/QrCodeGenerator.kt | 133 ++++++++---------- 3 files changed, 65 insertions(+), 94 deletions(-) diff --git a/app/src/main/java/com/sameerasw/medrop/domain/model/MeDropContact.kt b/app/src/main/java/com/sameerasw/medrop/domain/model/MeDropContact.kt index 6a01b3e..56606d5 100644 --- a/app/src/main/java/com/sameerasw/medrop/domain/model/MeDropContact.kt +++ b/app/src/main/java/com/sameerasw/medrop/domain/model/MeDropContact.kt @@ -70,8 +70,7 @@ data class MeDropContact( activeEntryIds: Set, customPhotoUri: String? = null, customDisplayName: String? = null, - fieldOverrides: Map = emptyMap(), - includeRev: Boolean = true + fieldOverrides: Map = emptyMap() ): String { val effectiveDisplayName = customDisplayName?.takeIf { it.isNotBlank() } ?: displayName val effectivePhotoUri = customPhotoUri ?: photoUri @@ -111,7 +110,6 @@ data class MeDropContact( (height * ratio).toInt().coerceAtLeast(1), true ) - } else { originalBitmap } @@ -191,10 +189,8 @@ data class MeDropContact( sb.appendLine("NOTE:${effNote.replace("\n", " ")}") } - if (includeRev) { - val rev = SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US).format(Date()) - sb.appendLine("REV:$rev") - } + val rev = SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US).format(Date()) + sb.appendLine("REV:$rev") sb.append("END:VCARD") return sb.toString() } diff --git a/app/src/main/java/com/sameerasw/medrop/ui/sheets/MeDropBottomSheet.kt b/app/src/main/java/com/sameerasw/medrop/ui/sheets/MeDropBottomSheet.kt index 6b8b0a0..a115783 100644 --- a/app/src/main/java/com/sameerasw/medrop/ui/sheets/MeDropBottomSheet.kt +++ b/app/src/main/java/com/sameerasw/medrop/ui/sheets/MeDropBottomSheet.kt @@ -251,22 +251,18 @@ fun MeDropBottomSheet( if (isQrModeActive && contact != null) { withContext(Dispatchers.IO) { val profile = safeSettings.getProfile(activeProfileType) - val qrEntryIds = safeSettings.getEffectiveEntryIds(activeProfileType).toMutableSet().apply { - remove("photo") // Photos are too large for QR codes and make the grid too dense - } val vcardString = contact.toVCard( context = context, - activeEntryIds = qrEntryIds, + activeEntryIds = safeSettings.getEffectiveEntryIds(activeProfileType), customPhotoUri = null, customDisplayName = if (activeProfileType != MeDropProfileType.CONTACT) profile.customDisplayName else null, - fieldOverrides = profile.customFieldOverrides, - includeRev = false + fieldOverrides = profile.customFieldOverrides ) val generated = QrCodeGenerator.generateQrBitmap( content = vcardString, - size = 1024, - foregroundColor = AndroidColor.WHITE, - backgroundColor = AndroidColor.BLACK, + size = 1000, + foregroundColor = AndroidColor.BLACK, + backgroundColor = AndroidColor.WHITE, logo = null ) withContext(Dispatchers.Main) { @@ -343,7 +339,7 @@ fun MeDropBottomSheet( val targetPhotoSize = if (isQrModeActive) 80.dp else (200.dp * scanScale) val qrContainerSize by animateDpAsState( - targetValue = if (isQrModeActive) 380.dp else targetPhotoSize, + targetValue = if (isQrModeActive) 340.dp else targetPhotoSize, animationSpec = androidx.compose.animation.core.spring( dampingRatio = androidx.compose.animation.core.Spring.DampingRatioMediumBouncy, stiffness = androidx.compose.animation.core.Spring.StiffnessLow diff --git a/app/src/main/java/com/sameerasw/medrop/utils/QrCodeGenerator.kt b/app/src/main/java/com/sameerasw/medrop/utils/QrCodeGenerator.kt index e88fb1c..ec6406a 100644 --- a/app/src/main/java/com/sameerasw/medrop/utils/QrCodeGenerator.kt +++ b/app/src/main/java/com/sameerasw/medrop/utils/QrCodeGenerator.kt @@ -9,110 +9,89 @@ import android.graphics.RectF import androidx.core.content.ContextCompat import com.google.zxing.BarcodeFormat import com.google.zxing.EncodeHintType -import com.google.zxing.WriterException import com.google.zxing.qrcode.QRCodeWriter import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import com.sameerasw.medrop.R +import java.util.EnumMap import kotlin.math.max -import java.util.HashMap -import java.util.Map - object QrCodeGenerator { fun generateQrBitmap( content: String, - size: Int =600, - foregroundColor: Int = Color.WHITE, - backgroundColor: Int = Color.BLACK, + size: Int = 600, + foregroundColor: Int = Color.BLACK, + backgroundColor: Int = Color.WHITE, logo: Bitmap? = null, - ): Bitmap? { - // Standard limit for alphanumeric QR codes with low error correction is 4,296 characters - // We use a safe limit of 2,953 to ensure reliability across all QR versions - if (content.trim().isEmpty() || content.length > 2953) { - return null + ): Bitmap { + val hints = EnumMap(EncodeHintType::class.java).apply { + put(EncodeHintType.CHARACTER_SET, "UTF-8") + put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H) + put(EncodeHintType.MARGIN, 2) } - try { - val writer = QRCodeWriter() - val hints: MutableMap = HashMap() - hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.L - hints[EncodeHintType.MARGIN] = 0 - val bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, size, size, hints) - - val moduleCount = bitMatrix.width - val moduleSize = size.toFloat() / moduleCount + val writer = QRCodeWriter() + val bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, size, size, hints) + val moduleCount = bitMatrix.width + val moduleSize = size.toFloat() / moduleCount - val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - canvas.drawColor(backgroundColor) + val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + canvas.drawColor(backgroundColor) - val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = foregroundColor - style = Paint.Style.FILL_AND_STROKE - strokeWidth = 0.8f - } + val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + color = foregroundColor + style = Paint.Style.FILL + } - val rect = RectF() + val rect = RectF() - for (y in 0 until moduleCount) { - for (x in 0 until moduleCount) { - if (bitMatrix.get(x, y)) { - // We add a tiny 0.5f overlap to ensure squares touch perfectly - // and appear "chunkier" by eliminating anti-aliased gaps. - val left = x * moduleSize - val top = y * moduleSize - val right = (x + 1) * moduleSize + 0.5f - val bottom = (y + 1) * moduleSize + 0.5f - rect.set(left, top, right, bottom) - canvas.drawRect(rect, paint) - } + for (y in 0 until moduleCount) { + for (x in 0 until moduleCount) { + if (bitMatrix.get(x, y)) { + val left = x * moduleSize + val top = y * moduleSize + val right = left + moduleSize + val bottom = top + moduleSize + rect.set(left, top, right, bottom) + canvas.drawRect(rect, paint) } } + } - if (logo != null) { - val logoSize = size * 0.20f - val logoMargin = (size - logoSize) / 2f - val badgeRect = - RectF(logoMargin, logoMargin, logoMargin + logoSize, logoMargin + logoSize) - - val badgeBgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = backgroundColor - style = Paint.Style.FILL - } - val badgeStrokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { - color = Color.parseColor("#26000000") - style = Paint.Style.STROKE - strokeWidth = 3f - } - canvas.drawOval(badgeRect, badgeBgPaint) - canvas.drawOval(badgeRect, badgeStrokePaint) + if (logo != null) { + val logoSize = size * 0.20f + val logoMargin = (size - logoSize) / 2f + val badgeRect = RectF(logoMargin, logoMargin, logoMargin + logoSize, logoMargin + logoSize) - val innerPadding = logoSize * 0.14f - val innerRect = RectF( - badgeRect.left + innerPadding, - badgeRect.top + innerPadding, - badgeRect.right - innerPadding, - badgeRect.bottom - innerPadding, - ) - canvas.drawBitmap( - logo, - null, - innerRect, - Paint(Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG) - ) + val badgeBgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + color = backgroundColor + style = Paint.Style.FILL } + val badgeStrokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + color = Color.parseColor("#26000000") + style = Paint.Style.STROKE + strokeWidth = 3f + } + canvas.drawOval(badgeRect, badgeBgPaint) + canvas.drawOval(badgeRect, badgeStrokePaint) - return bitmap - } catch (e: WriterException) { - return null + val innerPadding = logoSize * 0.14f + val innerRect = RectF( + badgeRect.left + innerPadding, + badgeRect.top + innerPadding, + badgeRect.right - innerPadding, + badgeRect.bottom - innerPadding, + ) + canvas.drawBitmap(logo, null, innerRect, Paint(Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG)) } + + return bitmap } fun getAppLogoBitmap(context: Context): Bitmap? { return try { - val drawable = - ContextCompat.getDrawable(context, R.mipmap.ic_launcher) ?: return null + val drawable = ContextCompat.getDrawable(context, R.mipmap.ic_launcher) ?: return null val bitmap = Bitmap.createBitmap( max(1, drawable.intrinsicWidth), max(1, drawable.intrinsicHeight),