diff --git a/java/src/org/futo/inputmethod/latin/LatinIME.kt b/java/src/org/futo/inputmethod/latin/LatinIME.kt
index ae136cb8a3625e3bd879e94336a497fb2bafb36b..09cbe2abbffd6f5b27b3643fbfe3c662dcaae3aa 100644
--- a/java/src/org/futo/inputmethod/latin/LatinIME.kt
+++ b/java/src/org/futo/inputmethod/latin/LatinIME.kt
@@ -315,7 +315,7 @@ class LatinIME : InputMethodServiceCompose(), LatinIMELegacy.SuggestionStripCont
         updateNavigationBarVisibility()
         settingsRefreshRequired = settingsRefreshRequired || refreshSettings
 
-        if(!uixManager.isMainKeyboardHidden) {
+        if(!uixManager.isMainKeyboardHidden.value) {
             println("Recreating keyboard")
             recreateKeyboard()
         } else {
diff --git a/java/src/org/futo/inputmethod/latin/uix/Action.kt b/java/src/org/futo/inputmethod/latin/uix/Action.kt
index 3bacc371bf10c3919e850c8e3e5fccacc44f951f..74d6ab09e25a60285570882851624f7ebe1c1f82 100644
--- a/java/src/org/futo/inputmethod/latin/uix/Action.kt
+++ b/java/src/org/futo/inputmethod/latin/uix/Action.kt
@@ -42,8 +42,6 @@ interface KeyboardManagerForAction {
     fun getContext(): Context
     fun getLifecycleScope(): LifecycleCoroutineScope
 
-    fun triggerContentUpdate()
-
     fun createInputTransaction(applySpaceIfNeeded: Boolean): ActionInputTransaction
 
     fun typeText(v: String)
diff --git a/java/src/org/futo/inputmethod/latin/uix/UixManager.kt b/java/src/org/futo/inputmethod/latin/uix/UixManager.kt
index 146999ecfa717280dd5b8f79bb5b452a00f7268f..777c7f5e971ab16eb4ea84be5cea61b88f40f46e 100644
--- a/java/src/org/futo/inputmethod/latin/uix/UixManager.kt
+++ b/java/src/org/futo/inputmethod/latin/uix/UixManager.kt
@@ -108,7 +108,6 @@ import org.futo.inputmethod.latin.suggestions.SuggestionStripViewListener
 import org.futo.inputmethod.latin.uix.actions.ActionEditor
 import org.futo.inputmethod.latin.uix.actions.ActionRegistry
 import org.futo.inputmethod.latin.uix.actions.AllActions
-import org.futo.inputmethod.latin.uix.actions.EmojiAction
 import org.futo.inputmethod.latin.uix.actions.KeyboardModeAction
 import org.futo.inputmethod.latin.uix.resizing.KeyboardResizers
 import org.futo.inputmethod.latin.uix.settings.DataStoreCacheProvider
@@ -182,8 +181,7 @@ fun Modifier.keyboardBottomPadding(size: ComputedKeyboardSize): Modifier = with(
 
 private class LatinIMEActionInputTransaction(
     private val inputLogic: InputLogic,
-    shouldApplySpace: Boolean,
-    private val context: Context
+    shouldApplySpace: Boolean
 ): ActionInputTransaction {
     private val isSpaceNecessary: Boolean
     private var isFinished = false
@@ -233,12 +231,8 @@ class UixActionKeyboardManager(val uixManager: UixManager, val latinIME: LatinIM
         return latinIME.lifecycleScope
     }
 
-    override fun triggerContentUpdate() {
-        uixManager.setContent()
-    }
-
     override fun createInputTransaction(applySpaceIfNeeded: Boolean): ActionInputTransaction {
-        return LatinIMEActionInputTransaction(latinIME.inputLogic, applySpaceIfNeeded, latinIME)
+        return LatinIMEActionInputTransaction(latinIME.inputLogic, applySpaceIfNeeded)
     }
 
     override fun typeText(v: String) {
@@ -277,7 +271,6 @@ class UixActionKeyboardManager(val uixManager: UixManager, val latinIME: LatinIM
     }
 
     override fun closeActionWindow() {
-        if(uixManager.currWindowActionWindow == null) return
         uixManager.returnBackToMainKeyboardViewFromAction()
     }
 
@@ -287,7 +280,7 @@ class UixActionKeyboardManager(val uixManager: UixManager, val latinIME: LatinIM
             Constants.SUGGESTION_STRIP_COORDINATE,
             Constants.SUGGESTION_STRIP_COORDINATE,
             false
-        );
+        )
     }
 
     override fun updateTheme(newTheme: ThemeOption) {
@@ -415,16 +408,16 @@ class UixManager(private val latinIME: LatinIME) {
     internal val composeView: ComposeView?
         get() = latinIME.composeView
 
-    private var shouldShowSuggestionStrip: Boolean = true
-    private var suggestedWords: SuggestedWords? = null
+    private var shouldShowSuggestionStrip = mutableStateOf(true)
+    private var suggestedWords: MutableState<SuggestedWords?> = mutableStateOf(null)
 
-    var currWindowAction: Action? = null
+    var currWindowAction: MutableState<Action?> = mutableStateOf(null)
     private var persistentStates: HashMap<Action, PersistentActionState?> = hashMapOf()
 
-    private var inlineSuggestions: List<MutableState<View?>> = listOf()
+    private var inlineSuggestions: MutableState<List<MutableState<View?>>> = mutableStateOf(emptyList())
     private val keyboardManagerForAction = UixActionKeyboardManager(this, latinIME)
 
-    private var mainKeyboardHidden = false
+    private var mainKeyboardHidden = mutableStateOf(false)
 
     private var numSuggestionsSinceNotice = 0
     private var currentNotice: MutableState<ImportantNotice?> = mutableStateOf(null)
@@ -450,9 +443,7 @@ class UixManager(private val latinIME: LatinIME) {
 
     var isInputOverridden = mutableStateOf(false)
 
-    var currWindowActionWindow: ActionWindow? = null
-    val isActionWindowDocked: Boolean
-        get() = currWindowActionWindow != null
+    var currWindowActionWindow: MutableState<ActionWindow?> = mutableStateOf(null)
 
     private var measuredTouchableHeight = 0
     val touchableHeight: Int
@@ -495,8 +486,8 @@ class UixManager(private val latinIME: LatinIME) {
 
         Column {
             // Don't show suggested words when it's not meant to be shown
-            val suggestedWordsOrNull = if(shouldShowSuggestionStrip) {
-                suggestedWords
+            val suggestedWordsOrNull = if(shouldShowSuggestionStrip.value) {
+                suggestedWords.value
             } else {
                 null
             }
@@ -505,7 +496,7 @@ class UixManager(private val latinIME: LatinIME) {
                 ActionBar(
                     suggestedWordsOrNull,
                     latinIME.latinIMELegacy as SuggestionStripViewListener,
-                    inlineSuggestions = inlineSuggestions,
+                    inlineSuggestions = inlineSuggestions.value,
                     onActionActivated = {
                         keyboardManagerForAction.performHapticAndAudioFeedback(
                             Constants.CODE_TAB,
@@ -534,67 +525,61 @@ class UixManager(private val latinIME: LatinIME) {
     private fun enterActionWindowView(action: Action) {
         assert(action.windowImpl != null)
 
-        currWindowAction = action
+        currWindowAction.value = action
 
         if (persistentStates[action] == null) {
             persistentStates[action] = action.persistentState?.let { it(keyboardManagerForAction) }
         }
 
-        currWindowActionWindow = (action.windowImpl!!)(keyboardManagerForAction, persistentStates[action])
+        currWindowActionWindow.value = (action.windowImpl!!)(keyboardManagerForAction, persistentStates[action])
 
-        mainKeyboardHidden = currWindowActionWindow?.onlyShowAboveKeyboard == false
+        mainKeyboardHidden.value = currWindowActionWindow.value?.onlyShowAboveKeyboard == false
 
         if(action.keepScreenAwake) {
             latinIME.window.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
         }
 
-        setContent()
-
         keyboardManagerForAction.announce("${latinIME.resources.getString(action.name)} mode")
     }
 
     fun returnBackToMainKeyboardViewFromAction() {
-        if(currWindowActionWindow == null) return
+        if(currWindowActionWindow.value == null) return
 
-        val name = latinIME.resources.getString(currWindowAction!!.name)
+        val name = latinIME.resources.getString(currWindowAction.value!!.name)
 
-        currWindowActionWindow!!.close()
+        currWindowActionWindow.value!!.close()
 
-        currWindowAction = null
-        currWindowActionWindow = null
+        currWindowAction.value = null
+        currWindowActionWindow.value = null
 
-        mainKeyboardHidden = false
+        mainKeyboardHidden.value = false
 
         latinIME.onKeyboardShown()
 
         latinIME.window.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
 
-        setContent()
-
         keyboardManagerForAction.announce("$name closed")
     }
 
     fun toggleExpandAction(to: Boolean? = null) {
-        mainKeyboardHidden = !(to ?: mainKeyboardHidden)
-        if(!mainKeyboardHidden) {
+        mainKeyboardHidden.value = !(to ?: mainKeyboardHidden.value)
+        if(!mainKeyboardHidden.value) {
             latinIME.onKeyboardShown()
         }
-
-        setContent()
     }
 
     @Composable
     private fun ActionViewWithHeader(windowImpl: ActionWindow) {
-        val heightDiv = if(mainKeyboardHidden) {
+        val heightDiv = if(mainKeyboardHidden.value) {
             1
         } else {
             1.5
         }
         Column {
-            if(mainKeyboardHidden || latinIME.isInputConnectionOverridden) {
+            if(mainKeyboardHidden.value || latinIME.isInputConnectionOverridden) {
                 ActionWindowBar(
                     onBack = { returnBackToMainKeyboardViewFromAction() },
-                    canExpand = currWindowAction!!.canShowKeyboard,
+                    canExpand = currWindowAction.value!!.canShowKeyboard,
                     onExpand = { toggleExpandAction() },
                     windowTitleBar = { windowImpl.WindowTitleBar(this) }
                 )
@@ -603,19 +588,19 @@ class UixManager(private val latinIME: LatinIME) {
             Box(modifier = Modifier
                 .fillMaxWidth()
                 .height(with(LocalDensity.current) {
-                    currWindowActionWindow?.fixedWindowHeight ?: ((latinIME
+                    currWindowActionWindow.value?.fixedWindowHeight ?: ((latinIME
                         .getInputViewHeight()
                         .toFloat() / heightDiv.toFloat()).toDp() +
                             if (actionsExpanded) ActionBarHeight else 0.dp)
                 })
                 .safeKeyboardPadding()
             ) {
-                windowImpl.WindowContents(keyboardShown = !isMainKeyboardHidden)
+                windowImpl.WindowContents(keyboardShown = !isMainKeyboardHidden.value)
             }
 
-            if(!mainKeyboardHidden && !latinIME.isInputConnectionOverridden) {
-                val suggestedWordsOrNull = if (shouldShowSuggestionStrip) {
-                    suggestedWords
+            if(!mainKeyboardHidden.value && !latinIME.isInputConnectionOverridden) {
+                val suggestedWordsOrNull = if (shouldShowSuggestionStrip.value) {
+                    suggestedWords.value
                 } else {
                     null
                 }
@@ -624,8 +609,8 @@ class UixManager(private val latinIME: LatinIME) {
                     onCollapse = { toggleExpandAction() },
                     onClose = { returnBackToMainKeyboardViewFromAction() },
                     words = suggestedWordsOrNull,
-                    showClose = currWindowActionWindow?.showCloseButton == true,
-                    showCollapse = currWindowActionWindow?.onlyShowAboveKeyboard == false,
+                    showClose = currWindowActionWindow.value?.showCloseButton == true,
+                    showCollapse = currWindowActionWindow.value?.onlyShowAboveKeyboard == false,
                     suggestionStripListener = latinIME.latinIMELegacy as SuggestionStripViewListener
                 )
             }
@@ -1023,8 +1008,8 @@ class UixManager(private val latinIME: LatinIME) {
             KeyboardWindowSelector { gap ->
                 Column {
                     when {
-                        currWindowActionWindow != null -> ActionViewWithHeader(
-                            currWindowActionWindow!!
+                        currWindowActionWindow.value != null -> ActionViewWithHeader(
+                            currWindowActionWindow.value!!
                         )
 
                         else -> MainKeyboardViewWithActionBar()
@@ -1032,7 +1017,7 @@ class UixManager(private val latinIME: LatinIME) {
 
                     Spacer(modifier = Modifier.height(gap))
 
-                    latinIME.LegacyKeyboardView(hidden = isMainKeyboardHidden)
+                    latinIME.LegacyKeyboardView(hidden = isMainKeyboardHidden.value)
 
                     if(latinIME.size.value !is FloatingKeyboardSize) {
                         Spacer(Modifier.height(navBarHeight()))
@@ -1137,19 +1122,16 @@ class UixManager(private val latinIME: LatinIME) {
     }
 
     fun closeActionWindow() {
-        if(currWindowActionWindow == null) return
         returnBackToMainKeyboardViewFromAction()
     }
 
 
     fun updateVisibility(shouldShowSuggestionsStrip: Boolean, fullscreenMode: Boolean) {
-        this.shouldShowSuggestionStrip = shouldShowSuggestionsStrip
-        setContent()
+        this.shouldShowSuggestionStrip.value = shouldShowSuggestionsStrip
     }
 
     fun setSuggestions(suggestedWords: SuggestedWords?, rtlSubtype: Boolean) {
-        this.suggestedWords = suggestedWords
-        setContent()
+        this.suggestedWords.value = suggestedWords
 
         if(currentNotice.value != null) {
             if(numSuggestionsSinceNotice > 1) {
@@ -1163,27 +1145,20 @@ class UixManager(private val latinIME: LatinIME) {
     fun onInlineSuggestionsResponse(response: InlineSuggestionsResponse): Boolean {
         currentNotice.value?.onDismiss(latinIME)
 
-        inlineSuggestions = response.inlineSuggestions.map {
+        inlineSuggestions.value = response.inlineSuggestions.map {
             latinIME.inflateInlineSuggestion(it)
         }
-        setContent()
 
         return true
     }
 
-    fun openEmojiKeyboard() {
-        if(currWindowAction == null) {
-            onActionActivated(EmojiAction)
-        }
-    }
-
     fun triggerAction(id: Int, alt: Boolean) {
         val action = AllActions.getOrNull(id) ?: throw IllegalArgumentException("No such action with ID $id")
 
         if(alt) {
             onActionAltActivated(action)
         } else {
-            if (currWindowAction != null && action.windowImpl != null) {
+            if (currWindowAction.value != null && action.windowImpl != null) {
                 closeActionWindow()
             }
 
@@ -1208,9 +1183,8 @@ class UixManager(private val latinIME: LatinIME) {
                 )
             } else {
                 listOf()
-            },
-            { }
-        )
+            }
+        ) { }
 
         val v = latinIME.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator?
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -1261,12 +1235,13 @@ class UixManager(private val latinIME: LatinIME) {
                 TutorialMode.None
         }
 
+    val currTutorialMode = mutableStateOf(TutorialMode.None)
     val tutorialArrowPosition: MutableState<LayoutCoordinates?> = mutableStateOf(null)
     val tutorialCompleted = mutableStateOf(false)
 
     @Composable
     private fun TutorialArrow() = with(LocalDensity.current) {
-        if(tutorialMode == TutorialMode.ResizerTutorial && !tutorialCompleted.value) {
+        if(currTutorialMode.value == TutorialMode.ResizerTutorial && !tutorialCompleted.value) {
             tutorialArrowPosition.value?.let { position ->
                 val pos = position.positionInWindow()
                 Icon(
@@ -1285,8 +1260,10 @@ class UixManager(private val latinIME: LatinIME) {
     }
 
     fun inputStarted(editorInfo: EditorInfo?) {
+        inlineSuggestions.value = emptyList()
         this.editorInfo = editorInfo
 
+        currTutorialMode.value = tutorialMode
         tutorialCompleted.value = false
         tutorialArrowPosition.value = null