From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: alina sireneva <alina@tei.su>
Date: Thu, 21 May 2026 03:04:57 +0400
Subject: somewhat handle theme changing in UniversalFragment-s

---
 .../ui/Components/UniversalFragment.java      | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/UniversalFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/UniversalFragment.java
index 0000000..0000000 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UniversalFragment.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UniversalFragment.java
@@ -18,6 +18,7 @@ import org.telegram.ui.ActionBar.BackDrawable;
 import org.telegram.ui.ActionBar.BaseFragment;
 import org.telegram.ui.ActionBar.INavigationLayout;
 import org.telegram.ui.ActionBar.Theme;
+import org.telegram.ui.ActionBar.ThemeDescription;
 import org.telegram.ui.Business.QuickRepliesController;
 import org.telegram.ui.ChatActivity;
 import org.telegram.ui.DialogsActivity;
@@ -72,6 +73,45 @@ public abstract class UniversalFragment extends BaseFragment {
         return fragmentView = contentView;
     }
 
+    // UniversalFragment enumerates no per-cell theme descriptions, so a theme switch (manual or
+    // auto-night) only repaints the action bar — cells that cache colors at construction keep
+    // stale colors. getThemeDescriptions() is re-invoked at the start of each theme animation;
+    // onAnimationProgress fires only during real theme animations (not fragment transitions). We
+    // recreate this fragment's views to pick up the new colors, but only once the animation has
+    // finished (progress >= 1) — mid-animation Theme.getColor() returns interpolated values, which
+    // would otherwise freeze the rebuilt views at a half-switched color.
+    @Override
+    public ArrayList<ThemeDescription> getThemeDescriptions() {
+        ArrayList<ThemeDescription> list = new ArrayList<>();
+        ThemeDescription.ThemeDescriptionDelegate delegate = new ThemeDescription.ThemeDescriptionDelegate() {
+            private boolean rebuilt;
+            @Override
+            public void didSetColor() {}
+            @Override
+            public void onAnimationProgress(float progress) {
+                if (rebuilt || progress < 1f) return;
+                rebuilt = true;
+                AndroidUtilities.runOnUIThread(UniversalFragment.this::inu_rebuildSelf);
+            }
+        };
+        list.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, delegate, Theme.key_windowBackgroundGray));
+        return list;
+    }
+
+    // recreate only this (top) fragment's views, preserving scroll. mirrors rebuildAllFragmentViews
+    // but scoped to self, since the delegate above only fires for the visible top fragment.
+    public void inu_rebuildSelf() {
+        INavigationLayout layout = getParentLayout();
+        if (layout == null) {
+            return;
+        }
+        saveScrollPosition();
+        clearViews();
+        setParentLayout(layout);
+        layout.showLastFragment();
+        applyScrolledPosition();
+    }
+
     protected abstract CharSequence getTitle();
     protected abstract void fillItems(ArrayList<UItem> items, UniversalAdapter adapter);
     protected abstract void onClick(UItem item, View view, int position, float x, float y);
