Skip to content

Instantly share code, notes, and snippets.

View johnkil's full-sized avatar
:octocat:

Evgenii Shishkin johnkil

:octocat:
View GitHub Profile
@johnkil
johnkil / EncryptedSettings.kt
Created July 17, 2025 11:48 — forked from AJIEKCX/EncryptedSettings.kt
A secure implementation of SharedPreferences for the MultiplatformSettings library
import android.content.SharedPreferences
import com.google.crypto.tink.Aead
import com.google.crypto.tink.KeysetHandle
import com.google.crypto.tink.RegistryConfiguration
import com.google.crypto.tink.TinkProtoKeysetFormat
import com.google.crypto.tink.aead.AeadConfig
import com.google.crypto.tink.aead.PredefinedAeadParameters
import com.google.crypto.tink.integration.android.AndroidKeystore
import com.google.crypto.tink.subtle.Base64
import com.google.crypto.tink.subtle.Hex
data class Event(
val id: Int,
val image: Image?,
val title: String,
val description: String?,
val areQuestionsAllowed: Boolean,
val startDate: Instant,
val endDate: Instant,
val organizer: User,
val address: EventLocation?,
import java.nio.file.*
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import kotlin.io.path.*
@OptIn(ExperimentalPathApi::class)
fun ZipOutputStream.addFolder(entryName: String, folder: Path) {
for (path in folder.walk()) {
val relativized = folder.relativize(path)
val prefix = if (entryName.isNotEmpty()) {
class SyncChallengesProgressUseCase @Inject constructor(
private val challengesRepository: ChallengesRepository,
private val getStepsFromFitnessApp: GetStepsFromFitnessAppUseCase,
getPhoneManufactureData: GetPhoneManufactureDataUseCase
) {
private val deviceId = getPhoneManufactureData().deviceId
suspend operator fun invoke(startDate: Instant): SyncChallengesProgressResult {
val now = Clock.System.now()
if (startDate.daysUntil(now, TimeZone.currentSystemDefault()) == 0) {
@Singleton
class OAuthTokenLocalDataSource @Inject constructor(
app: Application
) {
private val sharedPrefs: SharedPreferences = EncryptedSharedPreferences.create(
"oauth_token_local_data_source",
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
app,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
import android.util.Log
import com.bugsnag.android.Bugsnag
import timber.log.Timber
import java.util.*
class BugsnagTree : Timber.DebugTree() {
// Adding one to the initial size accounts for the add before remove.
private val buffer = ArrayDeque<String>(BUFFER_SIZE + 1)
override fun isLoggable(tag: String?, priority: Int): Boolean = priority >= Log.INFO

Задача: Спроектировать Дзен как продукт

  • умная лента
  • поиск*
  • 50 мил DAU
  • текстовые статьи, фото, видео
  • каналы ,можно подписаться
  • уведомления push
  • генерация контента
@johnkil
johnkil / InitAppUpdateFlow.kt
Created April 25, 2022 15:21
Support in-app updates
private fun initAppUpdateFlow() {
logcat { "check app update" }
val appUpdateManager = AppUpdateManagerFactory.create(this)
lifecycleScope.launch {
try {
appUpdateManager.requestUpdateFlow().collect(::onAppUpdateResult)
} catch (e: InstallException) {
logcat(LogPriority.ERROR) { "Failed to request app update flow\n${e.asLog()}" }
}
}
inline class CurrencyCode private constructor(private val isoCode: String) {
override fun toString(): String = isoCode
companion object {
fun from(isoCode: String): CurrencyCode {
require(isoCode.matches("^[A-Za-z]{3}$".toRegex())) {
"Invalid ISO 4217 currency code format: $isoCode"
}
return CurrencyCode(isoCode.toUpperCase(Locale.ROOT).intern())
class CompositeOnFocusChangeListener constructor(
vararg listeners: OnFocusChangeListener
) : OnFocusChangeListener, MutableSet<OnFocusChangeListener> by listeners.toMutableSet() {
override fun onFocusChange(view: View, hasFocus: Boolean) {
forEach { it.onFocusChange(view, hasFocus) }
}
}
fun View.addOnFocusChangeListener(listener: OnFocusChangeListener) {