Skip to content

Instantly share code, notes, and snippets.

View lucifer-thebeast's full-sized avatar
💭
I may be slow to respond.

Ronillo Ang lucifer-thebeast

💭
I may be slow to respond.
View GitHub Profile
@lucifer-thebeast
lucifer-thebeast / MemoryCacheManager.swift
Created April 27, 2024 01:02
MemoryCacheManager is a versatile and efficient in-memory cache manager crafted specifically for Swift iOS applications, with a focus on SwiftUI widget development. It provides a seamless solution for caching data to enhance the performance and responsiveness of SwiftUI widgets by minimizing load times.
class MemoryCacheManager<Key: Hashable, Value> {
private var cache: [Key: (value: Value, expiry: Date)]
private let defaultExpiryTime: TimeInterval
init(defaultExpiryTime: TimeInterval = 3600 * 6) { // Default expiry time is 6 hours
self.cache = [:]
self.defaultExpiryTime = defaultExpiryTime
}
@lucifer-thebeast
lucifer-thebeast / PressActionsModifier.swift
Created February 20, 2023 06:18 — forked from gabrieltheodoropoulos/PressActionsModifier.swift
PressActions modifier - Handle press and release events in SwiftUI
struct PressActions: ViewModifier {
var onPress: () -> Void
var onRelease: () -> Void
func body(content: Content) -> some View {
content
.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onChanged({ _ in
onPress()
@lucifer-thebeast
lucifer-thebeast / UIScrollWebView.swift
Created February 11, 2023 06:13
When you embed a WKWebView inside a UIScrollView in iOS, the size of the WKWebView may not change as expected because of conflicting constraints. Here's how to resolve it.
webView.scrollView.isScrollEnabled = false
webView.navigationDelegate = self
webView.loadHTMLString(htmlString, baseURL: nil)
scrollView.addSubview(webView)
...
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if webView.isLoading == false {
@lucifer-thebeast
lucifer-thebeast / DamerauLevenshteinDistance.swift
Created February 10, 2023 12:17
The Damerau–Levenshtein distance algorithm can be useful for name searching. It's a type of string metric that measures the difference between two strings, taking into account deletions, insertions, substitutions, and transpositions. This can be useful for fuzzy name matching, where you want to find close matches between two names even if they d…
import Foundation
func damerauLevenshteinDistance(s1: String, s2: String) -> Int {
let inf = s1.count + s2.count
var dp = [[Int]](repeating: [Int](repeating: inf, count: s2.count + 1), count: s1.count + 1)
for i in 0...s1.count {
dp[i][0] = i
}
for j in 0...s2.count {
dp[0][j] = j
@lucifer-thebeast
lucifer-thebeast / Graph.kt
Last active June 10, 2022 01:17
Kotlin standard library doesn't provide a graph data structure but we can create one.
data class Node(val name: String) {
val neighbors = mutableListOf<Edge>()
}
data class Edge(val neighbor: Node)
class Graph {
private val nodes = mutableListOf<Node>()
fun addNode(name: String) {
@lucifer-thebeast
lucifer-thebeast / LatestNewsViewModel.kt
Created June 9, 2022 02:32
How to consume a data from a Kotlin Coroutine Flow. Simply use the flow collect operator.
class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {
private val _data = MutableLiveData<List<ArticleHeadline>>()
val data: LiveData<List<GetNewsDetails>> = _data
fun getLatestNews() {
viewModelScope.launch {
val list = mutableListOf<ArticleHeadline>()
@lucifer-thebeast
lucifer-thebeast / NewsRepository.kt
Created June 9, 2022 02:19
If you want to filter a flow, modify a flow in Kotlin Coroutines... here's an example. We'll use the map and filter operators.
class NewsRepository(
private val newsRemoteDataSource: NewsRemoteDataSource,
private val userData: UserData
) {
/**
* Returns the favorite latest news applying transformations on the flow.
* These operations are lazy and don't trigger the flow. They just transform
* the current value emitted by the flow at that point in time.
*/
val favoriteLatestNews: Flow<List<ArticleHeadline>> =
@lucifer-thebeast
lucifer-thebeast / NewsRemoteDataSource.kt
Created June 9, 2022 02:07
n the following example, a data source fetches the latest news automatically at a fixed interval. As a suspend function cannot return multiple consecutive values, the data source creates and returns a flow to fulfill this requirement. In this case, the data source acts as the producer.
class NewsRemoteDataSource(
private val newsApi: NewsApi,
private val refreshIntervalMs: Long = 5000
) {
val latestNews: Flow<List<ArticleHeadline>> = flow {
while(true) {
val latestNews = newsApi.fetchLatestNews()
emit(latestNews) // Emits the result of the request to the flow
delay(refreshIntervalMs) // Suspends the coroutine for some time
}
@lucifer-thebeast
lucifer-thebeast / PodcastViewModel.kt
Last active June 8, 2022 06:30
How to update or recompose Jetpack Compose views. We'll use state as stated in the Android documentation. Here's an example.
class PodcastViewModel : ViewModel() {
private val _podcasts = MutableStateFlow(listOf<Podcast>())
val podcasts: StateFlow<List<Podcast>> get() = _podcasts
private val downloadQueue: MutableMap<Int, Flow<Int>> = mutableMapOf()
init {
getPodcasts()
}
@lucifer-thebeast
lucifer-thebeast / EmbeddedAndroidViewDemo.kt
Created June 8, 2022 04:49
How to embed traditional Android views inside Jetpack Compose
@Composable
fun EmbeddedAndroidViewDemo() {
Column {
// Holds state
val state = remember { mutableStateOf(0) }
// widget.ImageView
AndroidView(factory = { ctx ->