How to inject view model with Koin in Android

Issue #359 app/build.gradle implementation "org.koin:koin-core:$Version.koin" implementation "org.koin:koin-androidx-scope:$Version.koin" implementation "org.koin:koin-androidx-viewmodel:$Version.koin" MyApplication.kt import android.app.Application import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.core.context.startKoin import org.koin.dsl.module class MyApplication: Application() { var appModule = module { single { MyRepo() } viewModel { MyViewModel(get()) } } override fun onCreate() { super.onCreate() startKoin { androidLogger() androidContext(this@MyApplication) modules(appModule) } } } MyFragment.kt import org.koin.androidx.viewmodel.ext.android.viewModel val viewModel: MyViewModel by viewModel()

August 15, 2019 · 1 min · 61 words · Khoa

How to use coroutine LiveData in Android

Issue #358 app/build.gradle implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01" import androidx.lifecycle.ViewModel import androidx.lifecycle.liveData import kotlinx.coroutines.Dispatchers class MainViewModel : ViewModel() { val repository: TodoRepository = TodoRepository() val firstTodo = liveData(Dispatchers.IO) { val retrivedTodo = repository.getTodo(1) emit(retrivedTodo) } } Use coroutines with LiveData https://developer.android.com/topic/libraries/architecture/coroutines The liveData building block serves as a structured concurrency primitive between coroutines and LiveData. The code block starts executing when LiveData becomes active and is automatically canceled after a configurable timeout when the LiveData becomes inactive....

August 15, 2019 · 1 min · 200 words · Khoa

How to declare generic RecyclerView adapter in Android

Issue #357 generic/Adapter.kt package com.onmyway133.generic import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView abstract class Adapter<T>(var items: ArrayList<T>): RecyclerView.Adapter<RecyclerView.ViewHolder>() { abstract fun configure(item: T, holder: ViewHolder) fun update(items: ArrayList<T>) { this.items = items notifyDataSetChanged() } override fun getItemCount(): Int = items.count() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { val view = LayoutInflater .from(parent.context) .inflate(viewType, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { configure(items[position], holder as ViewHolder) } } class ViewHolder(view: View): RecyclerView....

August 14, 2019 · 1 min · 127 words · Khoa

How to use Payment Intent and Setup Intents with Stripe in iOS

Issue #356 StripeHandler.swift From Stripe 16.0.0 https://github.com/stripe/stripe-ios/blob/master/CHANGELOG.md#1600-2019-07-18 Migrates STPPaymentCardTextField.cardParams property type from STPCardParams to STPPaymentMethodCardParams final class StripeHandler { func createPaymentMethod( textField: STPPaymentCardTextField, completion: @escaping (Result<STPPaymentMethod, Error>) -> Void) { let paymentMethodParams = STPPaymentMethodParams( card: textField.cardParams, billingDetails: nil, metadata: nil ) STPAPIClient.shared().createPaymentMethod( with: paymentMethodParams, completion: { paymentMethod, error in DispatchQueue.main.async { if let paymentMethod = paymentMethod { completion(.success(paymentMethod)) } else { completion(.failure(error ?? AppError.request)) } } }) STPAPIClient.shared().createPaymentMethod( with: paymentMethodParams, completion: { paymentMethod, error in DispatchQueue....

August 14, 2019 · 4 min · 757 words · Khoa

How to format currency in Swift

Issue #355 final class CurrencyFormatter { func format(amount: UInt64, decimalCount: Int) -> String { let formatter = NumberFormatter() formatter.minimumFractionDigits = 0 formatter.maximumFractionDigits = decimalCount formatter.numberStyle = .decimal let value = Double(amount) / pow(Double(10), Double(decimalCount)) let fallback = String(format: "%.0f", value) return formatter.string(from: NSNumber(value: value)) ?? fallback } } class CurrencyFormatterTests: XCTestCase { func testFormat() { let formatter = CurrencyFormatter() // 120 USD XCTAssertEqual(formatter.format(amount: 120, decimalCount: 0), "120") // 12000 cents XCTAssertEqual(formatter....

August 13, 2019 · 1 min · 85 words · Khoa

How to simplify struct mutating in Swift

Issue #354 In Construction, we have a build method to apply closure to inout struct. We can explicitly define that with withValue func withValue<T>(_ value: T, closure: (inout T) -> Void) -> T { var mutableValue = value closure(&mutableValue) return mutableValue } So we can modify Protobuf structs easily user.book = withValue(Book()) { $0.price = 300 $0.author = withValue(Author()) { $0.name = "Thor" } }

August 13, 2019 · 1 min · 65 words · Khoa

How to not resign first responder for UITextField in iOS

Issue #353 When using STPPaymentCardTextField from stripe-ios, the default behavior is when we touch outside to dismiss keyboard, it checks and focus on number text field is it is invalid STPPaymentCardTextField.m - (STPFormTextField *)currentFirstResponderField { for (STPFormTextField *textField in [self allFields]) { if ([textField isFirstResponder]) { return textField; } } return nil; } - (BOOL)canResignFirstResponder { return [self.currentFirstResponderField canResignFirstResponder]; } - (BOOL)resignFirstResponder { [super resignFirstResponder]; BOOL success = [self.currentFirstResponderField resignFirstResponder]; [self layoutViewsToFocusField:nil animated:YES completion:nil]; [self updateImageForFieldType:STPCardFieldTypeNumber]; return success; } Then it calls [self....

August 13, 2019 · 1 min · 149 words · Khoa

How to use React JSX with Babel in Electron

Issue #352 For a normal electron app created with npm init, we can use all features of ES6, but not the JSX syntax for React. We can use just Babel to transpile JSX, as used in IconGenerator .babelrc { "plugins": [ "transform-react-jsx-source" ], "presets": ["env", "react"] } And in package.json, call babel to transpile src to dist "main": "dist/main.js", "scripts": { "start": "npm run babel && electron .", "babel": "babel ....

August 12, 2019 · 1 min · 97 words · Khoa

How to define version property in gradle

Issue #351 From Gradle tips and recipes, Configure project-wide properties For projects that include multiple modules, it might be useful to define properties at the project level and share them across all modules. You can do this by adding extra properties to the ext block in the top-level build.gradle file. ext { navigationVersion = "2.0.0" } rootProject.ext.navigationVersion Versions are used mostly in dependencies block so having them defined in global ext is not quite right....

August 10, 2019 · 1 min · 128 words · Khoa

How to use Firebase PhoneAuth in iOS

Issue #350 Read Authenticate with Firebase on iOS using a Phone Number Disable swizzling Info.plist <key>FirebaseAppDelegateProxyEnabled</key> <string>NO</string> Enable remote notification Enable Capability -> Background mode -> Remote notification AppDelegate.swift import Firebase import UIKit import FirebaseAuth @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { private let appFlowController = AppFlowController() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { UIApplication.shared.registerForRemoteNotifications() FirebaseApp.configure() return true } // MARK: - Remote Notification func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Auth....

August 7, 2019 · 1 min · 191 words · Khoa

How to use Navigation component with DrawerLayout in Android

Issue #349 build.gradle dependencies { classpath 'android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha05' } app/build.gradle apply plugin: 'androidx.navigation.safeargs' dependencies { def navigationVersion = "2.0.0" def drawerLayoutVersion = "1.0.0" implementation "androidx.drawerlayout:drawerlayout:$drawerLayoutVersion" implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion" implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion" } main_activity.xml Use CoordinatorLayout and ToolBar Define layout_gravity for NavigationView <?xml version="1.0" encoding="utf-8"?> <androidx.drawerlayout.widget.DrawerLayout android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawerLayout" tools:context=".MainActivity"> <androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <androidx.appcompat.widget.Toolbar android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:id="@+id/toolbar"/> </com.google.android.material.appbar.AppBarLayout> <fragment android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/hostFragment" android:name="androidx.navigation.fragment.NavHostFragment" app:defaultNavHost="true" app:navGraph="@navigation/navigation_graph"/> </androidx.coordinatorlayout.widget.CoordinatorLayout> <com.google.android.material.navigation.NavigationView android:layout_width="wrap_content" android:layout_height="match_parent" android:id="@+id/navigationView" android:fitsSystemWindows="true" android:layout_gravity="start" app:menu="@menu/drawer_menu"/> </androidx....

August 7, 2019 · 2 min · 376 words · Khoa

How to make digit passcode input in Swift

Issue #347 Add a hidden UITextField to view hierarchy, and add UITapGestureRecognizer to activate that textField. Use padding string with limit to the number of labels, and prefix to get exactly n characters. DigitView.swift import UIKit final class DigitView: UIView { lazy var stackView: UIStackView = { let view = UIStackView() view.axis = .horizontal view.distribution = .equalSpacing return view }() private(set) var boxes: [UIView] = [] private(set) var labels: [UILabel] = [] lazy var hiddenTextField: UITextField = { let textField = UITextField() textField....

August 6, 2019 · 2 min · 323 words · Khoa

How to make credit card input UI in Swift

Issue #346 We have FrontCard that contains number and expiration date, BackCard that contains CVC. CardView is used to contain front and back sides for flipping transition. We leverage STPPaymentCardTextField from Stripe for working input fields, then CardHandler is used to parse STPPaymentCardTextField content and update our UI. For masked credit card numbers, we pad string to fit 16 characters with ● symbol, then chunk into 4 parts and zip with labels to update....

August 5, 2019 · 3 min · 632 words · Khoa

How to stop implicit animation when title change on UIButton

Issue #345 UIButton with system type has implicit animation for setTitle(_:for:) Use this method to set the title for the button. The title you specify derives its formatting from the button’s associated label object. If you set both a title and an attributed title for the button, the button prefers the use of the attributed title over this one. At a minimum, you should set the value for the normal state....

August 2, 2019 · 1 min · 116 words · Khoa

How to use addSubview in iOS

Issue #344 addSubview can trigger viewDidLayoutSubviews, so be careful to just do layout stuff in viewDidLayoutSubviews This method establishes a strong reference to view and sets its next responder to the receiver, which is its new superview. Views can have only one superview. If view already has a superview and that view is not the receiver, this method removes the previous superview before making the receiver its new superview. When the bounds change for a view controller’€™s view, the view adjusts the positions of its subviews and then the system calls this method....

August 1, 2019 · 1 min · 146 words · Khoa

How to run app on beta iOS devices

Issue #343 Xcode 10.3 with iOS 13 sudo ln -s /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.0 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport Xcode 10.3 with iOS 13.1 beta 2 sudo ln -s /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.0/ /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.1 Use DeviceSupport Download and unzip Device support https://github.com/iGhibli/iOS-DeviceSupport /Applications/Xcode/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

August 1, 2019 · 1 min · 33 words · Khoa

How to submit electron app to AppStore

Issue #342 Before Install electron as dev npm install electron --save-dev Update electron-packager npm install electron-packager@latest --save-dev Use no space in app name Package with electron-packager Follow https://github.com/electron/electron-osx-sign/wiki/Packaging-and-Submitting-an-Electron-App-to-the-Mac-App-Store npx electron-packager . "MyApp" --app-bundle-id=com.onmyway133.MyApp --helper-bundle-id=com.onmyway133.MyApp.helper --app-version=1.4.0 --build-version=1.0.100 --platform=mas --arch=x64 --icon=Icon/Icon.icns --overwrite npx electron-osx-sign "MyApp-mas-x64/MyApp.app" --verbose npx electron-osx-flat "MyApp-mas-x64/MyApp.app" --verbose If you have multiple developer identities in your keychain: electron-osx-sign searches your keychain for the first signing certificates that it can locate. If you have multiple certificates then it may not know which cert you want to use for signing and you need to explicitly provide the name:...

July 31, 2019 · 2 min · 329 words · Khoa

How to format hour minute from time interval in Swift

Issue #340 Use DateComponentsFormatter https://nshipster.com/formatter/#datecomponentsformatter Results in no padding 0 func format(second: TimeInterval) -> String? { let formatter = DateComponentsFormatter() formatter.unitsStyle = .positional formatter.allowedUnits = [.hour, .minute] formatter.zeroFormattingBehavior = .pad return formatter.string(from: second) } XCTAssertEqual(format(second: 5400 ), "1:30") XCTAssertEqual(format(second: 7200), "2:00") XCTAssertEqual(format(second: 39600 ), "11:00") Use mod func format(minute: Int) -> String { let h = minute / 60 let m = minute % 60 return "\(h.padZero()):\(m.padZero())" } private extension Int { func padZero() -> String { return String(format: "%02d", self) } } XCTAssertEqual(format(minute: 90 ), "01:30") XCTAssertEqual(format(minute: 120), "02:00") XCTAssertEqual(format(minute: 660 ), "11:00")

July 31, 2019 · 1 min · 94 words · Khoa

My First Post

Hugo on Vercel

July 18, 2019 · 1 min · 3 words · Khoa

How to cache URLSession response

Issue #339 For simple cases, we don’t need to. Let’s use urlCache The URL cache for providing cached responses to requests within the session. Accessing Cached Data The URL Loading System caches responses both in memory and on disk, improving performance and reducing network traffic. The URLCache class is used for caching responses from network resources. Your app can directly access the shared cache instance by using the shared property of URLCache....

July 3, 2019 · 1 min · 92 words · Khoa