Trikot / kotlin multiplatform libraries

Overview

trikot

Latest version Kotlin CI License

Trikot / kotlin multiplatform libraries

Table of contents

Introduction

Trikot is a framework that helps building kotlin multiplatform apps. iOS, android and web are the primary targets.

Modules

Module Description
trikot.foundation Foundation classes and building blocks
trikot.streams Reactive streams
trikot.datasources Cascading data access layers abstraction.
trikot.http Multiplatform http client with native platform implementations.
trikot.graphql GraphQL query client built over trikot.http and trikot.datasources.
trikot.analytics Android and iOS analytics providers.
trikot.bluetooth Android and iOS bluetooth.
trikot.kword i18N with code generation for string keys.
trikot.viewmodels ViewModels for imperative frameworks (Android views and UIKit).
trikot.viewmodels.declarative ViewModels for declarative framework (Jetpack compose and SwiftUI).

Samples

License

Trikot is © 2018-2022 Mirego and may be freely distributed under the New BSD license. See the LICENSE.md file.

About Mirego

Mirego is a team of passionate people who believe that work is a place where you can innovate and have fun. We’re a team of talented people who imagine and build beautiful Web and mobile applications. We come together to share ideas and change the world.

We also love open-source software and we try to give back to the community as much as we can.

Comments
  • Prefix UIView extensions properties with

    Prefix UIView extensions properties with "trikot" for viewmodels

    Description

    All (or at least, the most used and problematic) public properties used for binding the ViewModels on UIView extensions are now prefixed with "trikot".

    Motivation and Context

    This prevents naming conflicts with host applications.

    How Has This Been Tested?

    Tested in my application. A simple rename in all UIViews did the trick :).

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [ ] New feature (non-breaking change which adds functionality)
    • [x] Breaking change (fix or feature that would cause existing functionality to change)
    opened by alarochelle 6
  • Update to Kotlin 1.7.20

    Update to Kotlin 1.7.20

    Description

    Update Trikot to Kotlin 1.7.20!

    We did not move to 1.7.22 due to some missing dependencies around Jetpack Compose that were blocking us, forcing us to split the dependencies into each version because we could not use 1.3.2 based on the RUNTIME as expected.

    Motivation and Context

    A few other projects using Trikot were already using 1.7.20 with great success. It's our time to shine and move forward as well!

    How Has This Been Tested?

    It got integrated as a Maven local dependency within our project that uses almost all platforms, including Javascript.

    Types of changes

    • [x] Bug fix (non-breaking change which fixes an issue)
    • [x] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)
    opened by Boubalou 3
  • Bump dependencies

    Bump dependencies

    Description

    Bump:

    • AtomicFu from 0.17.0 to 0.17.1
    • Jetpack Compose from 1.2.0-alpha03 to 1.2.0-alpha07
    • Kotlinx.Coroutines from 1.6.0 to 1.6.1
    • Ktor from 2.0.0-beta-1 to 2.0.0
    • Kotlin to 1.6.20
    opened by npresseault 3
  • [Streams] Coroutines interop with Publishers

    [Streams] Coroutines interop with Publishers

    Description

    Provide coroutine interop with Publishers This is a fork of https://github.com/Kotlin/kotlinx.coroutines/blob/master/reactive/kotlinx-coroutines-reactive/ with the following modifications:

    • It is now published as a KMM module, except for js target where there are some unbound symbols.
    • Removed JVM specific code and Reactor lib specific code.
    • Removed deprecated functions

    Motivation and Context

    This should serve as a bi-directional bridge between our reactive publishers and coroutine flows and channels.

    How Has This Been Tested?

    It hasn't been tested yet and will be a bit later. Unit tests from original codebase weren't ported either.

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [X] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)
    opened by npresseault 3
  • Add accessibility properties to ViewModel

    Add accessibility properties to ViewModel

    Description

    It was not possible to manage accessibility with our viewModel. While doing it in our project I took the opportunity to bring it in trikot.viewModel.

    Bonus : I also fixed the sample app that had a cell reuse problem on iOS.

    Motivation and Context

    • isAccessibilityElement: Publisher<Boolean> : Return true if it should be exposed as an accessibility element.
    • accessibilityLabel: Publisher<String> : String that identifies the accessibility element.
    • accessibilityHint: Publisher<ViewModelAccessibilityHint> : Describes the result of performing an action on the element.

    How Has This Been Tested?

    In the sample app

    Android

    https://user-images.githubusercontent.com/6673075/152240065-bfa50493-1563-4805-aef9-b352c4c0b64a.mp4

    iOS

    https://user-images.githubusercontent.com/6673075/152240098-8d47557c-699a-418c-93f8-a69801701494.mp4

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [x] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)
    opened by CharlesMcD 3
  • Add a DSL in order to ease view model creation

    Add a DSL in order to ease view model creation

    Description

    This provides a DSL in order to create common VM components, we can use it as follows:

    text("My label")
    localImage(ImageResource.MY_IMAGE)
    buttonWithText("My button" action = {}) 
    

    Instead of:

    VMDComponents.Text.withContent("My label", cancellableManager)
    VMDComponents.Image.local(ImageResource.MY_IMAGE, cancellableManager)
    VMDComponents.Button.withText("My button", cancellableManager)
    

    Motivation and Context

    Most of the time when creating view models we are already inside a VMDViewModelImpl context, so we should be able to create components view models easily without passing the cancellableManager  / coroutineScope everywhere. Using an interface we can easily extend the DSL with custom definitions inside each projects if needed. Also if we are in the context of a "content" class or anything other than a view model we just need to implement the interface in order to be able to use the DSL.

    How Has This Been Tested?

    This has been tested locally in other projects

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [X] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)
    opened by mathieularue 2
  • [New Module] Added VMD Compiler plugin

    [New Module] Added VMD Compiler plugin

    Description

    This new module is a Gradle plugin that uses annotation processing to generate the boilerplate code needed when using Trikot ViewModel Declarative (or its -flow variant).

    Motivation and Context

    Boilerplate code writing should be kept to a minimum. Code generation is sometime the solution.

    Adding a simple @Published annotation to a view model field will automatically generate a base class that contains all the code needed to make this field properly "published".

    How Has This Been Tested?

    The "stream" version of the plugin is used in a production project and has been battle tested. The Flow variation is more recent, and should be considered as "early alpha", since no project has actively used it yet.

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [x] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)
    opened by gbourassa 2
  • Fix/vmd labeled component fill max width

    Fix/vmd labeled component fill max width

    Description

    Removed the fillMaxWidth() from VMDLabeledComponent to give more control to the app

    Motivation and Context

    VMDSwitch and VMDCheckbox were forced to take the fullWidth when it's not always needed.

    How Has This Been Tested?

    The changes were tested in both sample apps

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [ ] New feature (non-breaking change which adds functionality)
    • [x] Breaking change (fix or feature that would cause existing functionality to change)

    *** Projects need to add fillMaxWidth to the modifier like it was added in the sample projects

    opened by nlangheit 2
  • [VMD] Animation engine

    [VMD] Animation engine

    Description

    This PR provides an engine to drive animations from common code.

    It supports all the basic types of animations:

    • Ease In
    • Ease Out
    • Ease In/Out
    • Custom Cubic Bezier
    • Spring

    This PR also:

    • Refactor sample's Home Screen to include sections
    • Adds a SwiftUI utility to use ForEach directly with VMDIdentifiableContent
    • Adds AtomicStackReference in trikot.foundation

    Motivation and Context

    Using the MVVM pattern it is pretty hard for a view to perform a change animated because the view layer don't have any insight on the type and context of a change. To alleviate that, we introduce the concept of animations in the view model layer.

    There is basically two ways to perform an animated change:

    Closure based

    A closure based version suitable when the change occur as a result of the press of a button or a specific lifecycle event. All the published properties updated within that block will be animated.

    withAnimation(VMDAnimation.Tween(duration = 1.seconds, easing = VMDAnimationEasing.Standard.EaseInEaseOut)) {
            // Perform the change here
    }
    

    Binding based

    If the change is introduced as part of a binding on a reactive chain, we also have the possibility to bind a value animated. Instead of providing only the value, we have to supply a pair of the value and an optional animation object. The exemple bellow animates the alpha value but does not animate the initial value and animates only the visible -> hidden transition while performing the hidden -> visible change without animation.

    bindHiddenAnimated(
        hiddenPublisher.withPreviousValue().map {
            val previousValue = it.first
            val value = it.second
            if (previousValue == null) { // No animation if its the first value received
                Pair(value, null)
            } else { // Optionally animate only some changes
                Pair(value, if (value) VMDAnimation.Tween() else null)
            }
        }
    )
    

    Usage in native code

    SwiftUI

    Since SwiftUI is able to automatically infer the updated properties and interpolate between them, there is no further step required for the animation to be effective. It is the equivalent of performing a change for a @State or an @ObservedObject within a withAnimation closure.

    Jetpack Compose

    It is a bit more effort on the Jetpack Compose side because the animation engine requires that we specifically declare an interpolator for a property to be animated.

    Example for animation of the alpha value

    val animatedHiddenProperty by viewModel.textField.observeAnimatedPropertyAsState(
        property = viewModel.textField::isHidden,
        transform = { hidden -> if (hidden) 0f else 1f }
    )
    val alphaAnimationProgress by animateFloatAsState(
        targetValue = animatedHiddenProperty.value,
        animationSpec = animatedHiddenProperty.animationSpec()
    )
    

    Notes

    The previous animation mechanism that was iOS only and that would animate all the changes no mater the type of change have been completely removed as it is nearly unused internally and it has just been introduced.

    Result

    iOS

    https://user-images.githubusercontent.com/291573/158255503-7b985480-776b-4c66-9726-54281c2c8c48.mp4

    Android

    https://user-images.githubusercontent.com/291573/158255555-3de5c3e2-fd39-43fd-b163-4797747620f5.mp4

    How Has This Been Tested?

    An animation showcase screen was added in the sample app.

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [x] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)
    opened by antoinelamy 2
  • [VMD] Fix crash in VMDButtonViewModel

    [VMD] Fix crash in VMDButtonViewModel

    Description

    Having the VMDButtonViewModel actionBlock as a var was causing freezing exception if the ViewModel was freeze before setting the action. The ViewModel was frozen more often than we imagined, only binding a property on the ViewModel is freezing the ViewModel and all of the objects around 😬

    Motivation and Context

    A regression was introduce in a previous modification and that regression was generating crashes everywhere 😬

    How Has This Been Tested?

    Tested in VMD sample project

    Types of changes

    • [X] Bug fix (non-breaking change which fixes an issue)
    • [ ] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)
    opened by hugolefrancois 2
  • `VMDButton.setAction()` execution overhead

    `VMDButton.setAction()` execution overhead

    Because setAction perform a subscribe on a publisher, setting an action on a large number of items becomes an expensive operation. If possible, refactor this so there is no unnecessary subscription for buttons that are not tapped.

    fun setAction(action: () -> Unit) {
        actionPublisher
            .observeOn(VMDDispatchQueues.uiQueue)
            .subscribe(
                cancellableManager,
                onNext = {
                    action()
                }
            )
    }
    
    viewmodels-declarative 
    opened by antoinelamy 2
  • [ViewModel] Implement accessibilityValue for slider

    [ViewModel] Implement accessibilityValue for slider

    We should add a string that represents the current value of the accessibility element.

    From the documentation

    The value is a localized string that contains the current value of an element. For example, the value of a slider might be 9.5 or 35% and the value of a text field is the text it contains.

    Use the value property only when an accessibility element can have a value that is not represented by its label. For example, a volume slider’s label might be “Volume,” but its value is the current volume level. In this case, it’s not enough for users to know the identity of the slider, because they also need to know its current value.

    enhancement 
    opened by CharlesMcD 0
  • [ViewModel] Implement UIAccessibilityTraitButton

    [ViewModel] Implement UIAccessibilityTraitButton

    When using a simple ViewModel instead of a ButtonViewModel, we don't see any of the buttons being described as "button", because the view model is bound to plain views. One way to fix this is to force the accessibility role or trait.

    On iOS, you simply add the UIAccessibilityTraitButton trait to the accessibilityTraits value: view.accessibilityTraits |= .button

    On Android, it's a bit more complicated, you have to use an accessibilityDelegate to force the class name, or override view.onInitializeAccessibilityNodeInfo

    ViewCompat.setAccessibilityDelegate(model, object : AccessibilityDelegateCompat() {
        override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfoCompat) {
            super.onInitializeAccessibilityNodeInfo(host, info)
            info.className = android.widget.Button::class.java.name
        }
    

    This wouldn't be necessary it the button view model were attached to actual button views.

    Thanks @dominiclabbe for the proposition!

    enhancement 
    opened by CharlesMcD 0
  • Trikot.viewmodels DefaultImageViewModelHandler is leaking subscription to imageFlow

    Trikot.viewmodels DefaultImageViewModelHandler is leaking subscription to imageFlow

    Assigning an ImageViewModel to a UIImageView does not cancel the subscription to the viewModel's imageFlow when the UIView is deallocated.

    class MyView: UIView {
    
        private let myImageView = UIImageView()
    
        var myViewModel: MyViewModel {
            didSet {
                 myImageView.imageViewModel = myViewModel.imageViewModel
            }
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
    
            addSubview(myImageView)   
        }
    
        deinit {
            // We need to manually set the image's viewModel to nil, otherwise the subscription to the imageFlow is never cancelled
            myViewModel.imageViewModel = nil
        }
    }
    
    bug viewmodels 
    opened by marcantoinefortier 0
Releases(4.1.0)
  • 4.1.0(Dec 19, 2022)

    Updates

    • Kotlin to 1.7.20
    • AtomicFu to 0.18.5
    • Jetpack Compose to 1.3.x
    • Ktor to 2.0.3
    • Kotlin Serialization to 1.4.1
    • Kotlin Wrappers extensions to 1.0.1-pre.459
    Source code(tar.gz)
    Source code(zip)
  • 4.0.0(Dec 19, 2022)

    Breaking Changes

    • iOS/tvOS minimum deployment target is now 12.0
    • [datasources] Moved Trikot.Datasources to Trikot.Datasources.streams
      To migrate:
      • Update com.mirego.trikot:datasources:$trikot_version for com.mirego.trikot:datasources-streams:$trikot_version
      • Add export("com.mirego.trikot:datasources-core:$trikot_version")
    • [datasources-flow] New implementation that supports flows and coroutines
    • [VMD] Removed Modifier.fillMaxWidth in VMDLabeledComponent
      • UI using VMDCheckbox and VMDSwitch should add fillMaxWidth to the modifier
    • [VMD-flow] Removed Modifier.fillMaxWidth in VMDLabeledComponent
      • UI using VMDCheckbox and VMDSwitch should add fillMaxWidth to the modifier
    • [viewmodels] UIView extensions properties are now prefixed with "trikot" on iOS and tvOS
      • UIButton.buttonViewModel is now trikotButtonViewModel
      • UIImage.imageViewModel is now trikotImageViewModel
      • UILabel.labelViewModel is now trikotLabelViewModel
      • UIPicker.pickerViewModel is now trikotPickerViewModel
      • UISlider.sliderViewModel is now trikotSliderViewModel
      • UISwitch.toggleSwitchViewModel is now trikotToggleSwitchViewModel
      • UITextField.inputTextViewModel is now trikotInputTextViewModel
      • UITextView.labelViewModel is now trikotLabelViewModel
      • UIView.viewModel is now trikotViewModel
      • UIView.trikotViewModel() is now getTrikotViewModel()

    Updates

    • [VMD/VMD-flow] Add a DSL in order to ease view model creation
    • [VMD/VMD-flow] Snackbar component
    • [VMD/VMD-flow] Add Picker component
    • [VMD/VMD-flow] Add callback to RemoteImage in VMDImage to know when the resource is loaded on Android
    • [VMD-flow] Provide a BasicTextField binding for android
    • [VMD-flow] Add support for use of FlowI18N in VMDComponents factory
    • [VMD-flow] Backport and fix some functionalities [VMD-flow] Improved handling of lifecycle on both android and iOS
    • [VMD-compiler] New Gradle plugin to generate declarative Viewmodels boilerplate code
    • [analytics] Add distinctAppId to the AnalyticsService
    • [datasources] Improvement to BaseHotDataSource
    • [datasources] Re-implement with flows and coroutines
    • [datasources-flow] Fix pending state while refreshing
    • [kword] Add support for dynamic framework resource lookup fallback

    Fixes

    • [VMD] Fix Jetpack Compose progress views configuration propagation
    • [VMD/VMD-flow] Prevent crashing on too large bitmap in VMDImage on Android
    • [VMD-flow] Fix ButtonViewModel setAction staying subscribed
    • [VMD-flow] willChange and didChange need to be synchronous to work with the VMDAnimationContext.animationStack
    • [viewmodels] Add missing transformation on Android drawable
    • [bluetooth] Update Bluetooth permission requirements for Android depending on OS version
    • [bluetooth] Make toList conversion thread safe by cloning map before converting its values to list
    • [datasources-flow] Change delete/clear cache cancellation behavior
    Source code(tar.gz)
    Source code(zip)
Owner
Mirego
We want to build the greatest team, the best workplace and a better world.
Mirego
An awesome collaborative collection of Kotlin Multiplatform libraries

Awesome Kotlin Multiplatform Awesome Projects Updated 33 November 21, 2021 Contents Guides Dependency Injection Database NoSQL SQL Extension Reactive

Matteo Crippa 5 Dec 12, 2022
🧸 A multiplatform coroutine-based wrapper for popular platform-specific Redis client libraries

?? rekt ⚠️ WARNING! This project is experimental and may be missing essential features. Please let us know if you found any issues or have any suggest

Hexalite Network 3 Aug 31, 2022
🧸 A multiplatform coroutine-based wrapper for popular platform-specific Redis client libraries

?? rekt ⚠️ WARNING! This project is experimental and may be missing essential features. Please let us know if you found any issues or have any suggest

Southdust Team 3 Aug 31, 2022
Run Kotlin/JS libraries in Kotlin/JVM and Kotlin/Native programs

Zipline This library streamlines using Kotlin/JS libraries from Kotlin/JVM and Kotlin/Native programs. It makes it possible to do continuous deploymen

Cash App 1.5k Dec 30, 2022
🔨 Template for easy hosting of your Java/Kotlin libraries on GitHub

?? kotlin-jvm-library-template Another template for easy hosting your Java/Kotlin libraries on GitHub. Features boilerplate for Kotlin/Java projects w

Viktor 0 Jan 7, 2022
Android project setup files when developing apps from scratch. The codebase uses lates jetpack libraries and MVVM repository architecture for setting up high performance apps

Android architecture app Includes the following Android Respository architecture MVVM Jepack libraries Carousel view Kotlin Kotlin Flow and Livedata P

null 2 Mar 31, 2022
An awesome list that curates the best KMM libraries, tools and more.

Awesome KMM Kotlin Multiplatform Mobile (KMM) is an SDK designed to simplify creating cross-platform mobile applications. With the help of KMM, you ca

Konstantin 994 Dec 28, 2022
Automatically empty the trash in all of your Plex libraries

Plex Auto Trash Automatically empty the trash in all of your Plex libraries. If you disable automatic trash emptying (and you probably should) trash s

Jake Wharton 25 Aug 11, 2022
Account-lib - A suite of libraries to facilitate the usage of account-sdk

Usage Clone this repository (skip this step if the repo is on your local machine). The default branch is fine. git clone https://github.com/AFBlockcha

null 0 May 24, 2022
A personal project made using Jetpack Compose, Clean-MVVM architecture and other jetpack libraries

A basic CRUD for recording your personal credit and debit transactions. Made using Jetpack Compose, Clean-MVVM and other Jetpack libraries, incorporated with Unit Tests.

Shoaib Ahmed 3 Dec 6, 2022
The AppMetrica Push SDK is a set of libraries for working with push notifications.

Flutter AppMetrica Push AppMetrica Push SDK — это набор библиотек для работы с push-уведомлениями. Подключив AppMetrica Push SDK, вы можете создать и

Mad Brains 6 Oct 12, 2022
Boilerplate code for implementing MVVM in Android using Jetpack libraries, coroutines, dependency injection and local persistance

MVVM Foundation This projects aims to speed up development of Android apps by providing a solid base to extend Libraries Jetpack Fragment Material3 :

Gabriel Gonzalez 2 Nov 10, 2022
Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in Kotlin with Jetpack Compose and a backed in Kotlin hosted on AppEngine.

Conferences4Hall Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in K

Gérard Paligot 98 Dec 15, 2022
Opinionated Redux-like implementation backed by Kotlin Coroutines and Kotlin Multiplatform Mobile

CoRed CoRed is Redux-like implementation that maintains the benefits of Redux's core idea without the boilerplate. No more action types, action creato

Kittinun Vantasin 28 Dec 10, 2022
An app architecture for Kotlin/Native on Android/iOS. Use Kotlin Multiplatform Mobile.

An app architecture for Kotlin/Native on Android/iOS. Use Kotlin Multiplatform Mobile. 项目架构主要分为原生系统层、Android/iOS业务SDK层、KMM SDK层、KMM业务逻辑SDK层、iOS sdkfra

libill 4 Nov 20, 2022
A Bluetooth kotlin multiplatform "Cross-Platform" library for iOS and Android

Blue-Falcon A Bluetooth "Cross Platform" Kotlin Multiplatform library for iOS, Android, MacOS, Raspberry Pi and Javascript. Bluetooth in general has t

Andrew Reed 220 Dec 28, 2022
Mobile client for official Nextcloud News App written as Kotlin Multiplatform Project

Newsout Android and iOS mobile client for Nextcloud news App. The Android client is already available to download in the Play Store. F-Droid and Apple

Simon Schubert 118 Oct 3, 2022
Kotlin Multiplatform Application to show Crypto Coins

This is the codebase of Crypto currency Tracking Kotlin Multiplatform App. Components Shared Components Ktor (Network Client) SQL Delight (Local DB) A

Aman Bansal 10 Oct 31, 2022
Dependency Injection library for Kotlin Multiplatform, support iOS and Android

Multiplatform-DI library for Kotlin Multiplatform Lightweight dependency injection framework for Kotlin Multiplatform application Dependency injection

Anna Zharkova 32 Nov 10, 2022