From b8fbcfef69ff47f8ff9eb40cea206ef8df356c0e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 25 Nov 2025 10:55:30 +0000
Subject: [PATCH 1/3] Initial plan
From 2fa1ab002f51d6202ea7938d0b8cc42c6350eeb7 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 25 Nov 2025 11:03:55 +0000
Subject: [PATCH 2/3] feat: Add light and dark theme support
Co-authored-by: pushpender-singh-ap <73298854+pushpender-singh-ap@users.noreply.github.com>
---
App.js | 17 ++--
src/Navigation/BottomNavigation.js | 8 +-
src/Redux/Reducers/index.js | 6 ++
src/Screens/Settings/index.js | 125 +++++++++++++++++++++++++++--
src/Theme/ThemeContext.js | 76 ++++++++++++++++++
src/Theme/colors.js | 120 +++++++++++++++++++++++++++
src/Theme/index.js | 1 +
7 files changed, 337 insertions(+), 16 deletions(-)
create mode 100644 src/Theme/ThemeContext.js
create mode 100644 src/Theme/colors.js
create mode 100644 src/Theme/index.js
diff --git a/App.js b/App.js
index dc67a6a..f2d598a 100644
--- a/App.js
+++ b/App.js
@@ -13,6 +13,7 @@ import {CONFIGCAT_SDK_KEY_TEST, CONFIGCAT_SDK_KEY_PROD} from '@env';
import {BannerProvider} from './src/Components/UIComp/AnimeAdBanner/BannerContext';
import crashlytics from '@react-native-firebase/crashlytics';
import analytics from '@react-native-firebase/analytics';
+import {ThemeProvider} from './src/Theme';
/**
* The main App component that sets up the root of the application.
@@ -54,13 +55,15 @@ const App = () => {
sdkKey={__DEV__ ? CONFIGCAT_SDK_KEY_TEST : CONFIGCAT_SDK_KEY_PROD}>
} persistor={persistor}>
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/src/Navigation/BottomNavigation.js b/src/Navigation/BottomNavigation.js
index 71a3122..d3427bc 100644
--- a/src/Navigation/BottomNavigation.js
+++ b/src/Navigation/BottomNavigation.js
@@ -14,6 +14,7 @@ import {View, StyleSheet} from 'react-native';
import {useFeatureFlag} from 'configcat-react';
import LinkListScreen from '../InkNest-Externals/Screens/Webview/LinkListScreen';
import FloatingDonationButton from '../InkNest-Externals/Donation/FloatingDonationButton';
+import {useTheme} from '../Theme';
const BottomTab = createBottomTabNavigator();
@@ -78,6 +79,7 @@ const TabBarIcon = props => {
*/
export function BottomNavigation() {
const {value: forIosValue} = useFeatureFlag('forIos', 'Default');
+ const {colors} = useTheme();
return (
<>
@@ -88,14 +90,14 @@ export function BottomNavigation() {
style={[
StyleSheet.absoluteFill,
{
- backgroundColor: '#110918',
+ backgroundColor: colors.tabBar,
},
]}
/>
),
headerShown: false,
- tabBarActiveTintColor: '#D2D2D6',
- tabBarInactiveTintColor: '#6B666D',
+ tabBarActiveTintColor: colors.tabBarActive,
+ tabBarInactiveTintColor: colors.tabBarInactive,
tabBarStyle: {
paddingVertical: 4,
},
diff --git a/src/Redux/Reducers/index.js b/src/Redux/Reducers/index.js
index 4c73172..927eb0a 100644
--- a/src/Redux/Reducers/index.js
+++ b/src/Redux/Reducers/index.js
@@ -14,6 +14,7 @@ const initialState = {
DownloadComic: {},
scrollPreference: 'horizontal', // Default scroll mode is horizontal
hasRewardAdsShown: false,
+ themeMode: 'system', // Theme mode: 'light', 'dark', or 'system'
};
/**
@@ -200,6 +201,10 @@ const Reducers = createSlice({
// Update the flag indicating whether reward ads have been shown
state.hasRewardAdsShown = action.payload;
},
+ setThemeMode: (state, action) => {
+ // Update the theme mode: 'light', 'dark', or 'system'
+ state.themeMode = action.payload;
+ },
},
});
@@ -224,5 +229,6 @@ export const {
clearHistory,
setScrollPreference,
rewardAdsShown,
+ setThemeMode,
} = Reducers.actions;
export default Reducers.reducer;
diff --git a/src/Screens/Settings/index.js b/src/Screens/Settings/index.js
index a784a52..7e17653 100644
--- a/src/Screens/Settings/index.js
+++ b/src/Screens/Settings/index.js
@@ -27,23 +27,136 @@ import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import {NAVIGATION} from '../../Constants';
import Header from '../../Components/UIComp/Header';
import {useDispatch, useSelector} from 'react-redux';
-import {setScrollPreference} from '../../Redux/Reducers';
+import {setScrollPreference, setThemeMode} from '../../Redux/Reducers';
import DonationBanner from '../../InkNest-Externals/Donation/DonationBanner';
+import {useTheme} from '../../Theme';
+
+/**
+ * Get the display label for the current theme mode
+ * @param {string} mode - The theme mode ('light', 'dark', or 'system')
+ * @returns {string} The display label
+ */
+const getThemeModeLabel = mode => {
+ switch (mode) {
+ case 'light':
+ return 'Light';
+ case 'dark':
+ return 'Dark';
+ case 'system':
+ default:
+ return 'System';
+ }
+};
+
+/**
+ * Get the icon name for the current theme mode
+ * @param {string} mode - The theme mode ('light', 'dark', or 'system')
+ * @returns {string} The icon name
+ */
+const getThemeModeIcon = mode => {
+ switch (mode) {
+ case 'light':
+ return 'white-balance-sunny';
+ case 'dark':
+ return 'moon-waning-crescent';
+ case 'system':
+ default:
+ return 'theme-light-dark';
+ }
+};
export function Settings({navigation}) {
const dispatch = useDispatch();
const scrollPreference = useSelector(state => state.data.scrollPreference);
+ const themeMode = useSelector(state => state.data.themeMode) || 'system';
+ const {colors} = useTheme();
+
+ /**
+ * Cycle through theme modes: system -> light -> dark -> system
+ */
+ const handleThemeToggle = () => {
+ analytics().logEvent('toggle_theme_mode', {
+ item: 'Theme Mode',
+ currentMode: themeMode,
+ });
+
+ let newMode;
+ switch (themeMode) {
+ case 'system':
+ newMode = 'light';
+ break;
+ case 'light':
+ newMode = 'dark';
+ break;
+ case 'dark':
+ default:
+ newMode = 'system';
+ break;
+ }
+
+ dispatch(setThemeMode(newMode));
+
+ Alert.alert(
+ 'Theme Changed',
+ `App theme is now set to ${getThemeModeLabel(newMode)}.`,
+ [{text: 'OK'}],
+ );
+ };
return (
-
-
+
+
+
+
+
+ Theme
+
+
+
+ {getThemeModeLabel(themeMode)}
+
+
+
+
About us
diff --git a/src/Theme/ThemeContext.js b/src/Theme/ThemeContext.js
new file mode 100644
index 0000000..af8b239
--- /dev/null
+++ b/src/Theme/ThemeContext.js
@@ -0,0 +1,76 @@
+import React, {createContext, useContext, useMemo} from 'react';
+import {useSelector} from 'react-redux';
+import {useColorScheme} from 'react-native';
+import {lightColors, darkColors} from './colors';
+
+/**
+ * @typedef {'light' | 'dark' | 'system'} ThemeMode
+ */
+
+/**
+ * Theme context that provides the current theme colors and mode information.
+ */
+const ThemeContext = createContext({
+ colors: darkColors,
+ isDark: true,
+ themeMode: 'system',
+});
+
+/**
+ * ThemeProvider component that wraps the application and provides theme context.
+ * It reads the theme preference from Redux store and the system color scheme
+ * to determine the current theme.
+ *
+ * @param {Object} props - Component props
+ * @param {React.ReactNode} props.children - Child components
+ * @returns {JSX.Element} The provider component wrapping children
+ */
+export function ThemeProvider({children}) {
+ const systemColorScheme = useColorScheme();
+ const themeMode = useSelector(state => state.data.themeMode) || 'system';
+
+ const {colors, isDark} = useMemo(() => {
+ let isDarkTheme;
+
+ if (themeMode === 'system') {
+ isDarkTheme = systemColorScheme === 'dark';
+ } else {
+ isDarkTheme = themeMode === 'dark';
+ }
+
+ return {
+ colors: isDarkTheme ? darkColors : lightColors,
+ isDark: isDarkTheme,
+ };
+ }, [themeMode, systemColorScheme]);
+
+ const value = useMemo(
+ () => ({
+ colors,
+ isDark,
+ themeMode,
+ }),
+ [colors, isDark, themeMode],
+ );
+
+ return (
+ {children}
+ );
+}
+
+/**
+ * Custom hook to access the current theme context.
+ * Must be used within a ThemeProvider.
+ *
+ * @returns {{ colors: typeof darkColors, isDark: boolean, themeMode: string }}
+ * The current theme colors, dark mode flag, and theme mode setting
+ */
+export function useTheme() {
+ const context = useContext(ThemeContext);
+ if (!context) {
+ throw new Error('useTheme must be used within a ThemeProvider');
+ }
+ return context;
+}
+
+export {lightColors, darkColors};
diff --git a/src/Theme/colors.js b/src/Theme/colors.js
new file mode 100644
index 0000000..110bc48
--- /dev/null
+++ b/src/Theme/colors.js
@@ -0,0 +1,120 @@
+/**
+ * Theme color definitions for Light and Dark modes.
+ * These colors are used throughout the application to maintain consistent theming.
+ */
+
+export const lightColors = {
+ // Primary backgrounds
+ primary: '#FFFFFF',
+ secondary: '#F5F5F5',
+ background: '#FFFFFF',
+ surface: '#F8F8F8',
+
+ // Text colors
+ text: '#000000',
+ textSecondary: '#666666',
+ textMuted: '#999999',
+
+ // UI elements
+ card: '#FFFFFF',
+ cardBorder: '#E0E0E0',
+ border: '#E0E0E0',
+ divider: '#E0E0E0',
+
+ // Navigation
+ tabBar: '#FFFFFF',
+ tabBarActive: '#5B67F1',
+ tabBarInactive: '#999999',
+ headerBackground: '#FFFFFF',
+ headerBorder: '#E0E0E0',
+
+ // Buttons and interactive elements
+ buttonPrimary: '#5B67F1',
+ buttonPrimaryText: '#FFFFFF',
+ buttonSecondary: 'rgba(91, 103, 241, 0.1)',
+ buttonSecondaryText: '#5B67F1',
+
+ // Status colors
+ success: '#4CAF50',
+ warning: '#FF9800',
+ error: '#F44336',
+ info: '#2196F3',
+
+ // Accent colors
+ accent: '#5B67F1',
+ accentLight: 'rgba(91, 103, 241, 0.2)',
+
+ // Overlay colors
+ overlay: 'rgba(0, 0, 0, 0.5)',
+ overlayLight: 'rgba(0, 0, 0, 0.1)',
+
+ // Loading and skeleton
+ skeleton: '#E0E0E0',
+ loadingBackground: 'rgba(255, 255, 255, 0.9)',
+
+ // Icon colors
+ icon: '#000000',
+ iconSecondary: '#666666',
+
+ // Settings specific
+ settingsItem: '#FFFFFF',
+ settingsItemText: '#000000',
+};
+
+export const darkColors = {
+ // Primary backgrounds
+ primary: '#14142A',
+ secondary: '#1C1C3A',
+ background: '#14142A',
+ surface: '#1E1E3C',
+
+ // Text colors
+ text: '#FFFFFF',
+ textSecondary: 'rgba(255, 255, 255, 0.7)',
+ textMuted: 'rgba(255, 255, 255, 0.5)',
+
+ // UI elements
+ card: 'rgba(255, 255, 255, 0.05)',
+ cardBorder: 'rgba(255, 255, 255, 0.1)',
+ border: 'rgba(255, 255, 255, 0.1)',
+ divider: 'rgba(255, 255, 255, 0.1)',
+
+ // Navigation
+ tabBar: '#110918',
+ tabBarActive: '#D2D2D6',
+ tabBarInactive: '#6B666D',
+ headerBackground: '#14142A',
+ headerBorder: 'rgba(255, 255, 255, 0.5)',
+
+ // Buttons and interactive elements
+ buttonPrimary: '#5B67F1',
+ buttonPrimaryText: '#FFFFFF',
+ buttonSecondary: 'rgba(91, 103, 241, 0.3)',
+ buttonSecondaryText: '#FFFFFF',
+
+ // Status colors
+ success: '#4CAF50',
+ warning: '#FF9800',
+ error: '#F44336',
+ info: '#2196F3',
+
+ // Accent colors
+ accent: '#5B67F1',
+ accentLight: 'rgba(91, 103, 241, 0.2)',
+
+ // Overlay colors
+ overlay: 'rgba(20, 20, 42, 0.8)',
+ overlayLight: 'rgba(255, 255, 255, 0.06)',
+
+ // Loading and skeleton
+ skeleton: 'rgba(255, 255, 255, 0.1)',
+ loadingBackground: 'rgba(20, 20, 42, 0.9)',
+
+ // Icon colors
+ icon: '#FFFFFF',
+ iconSecondary: 'rgba(255, 255, 255, 0.7)',
+
+ // Settings specific
+ settingsItem: '#FFFFFF',
+ settingsItemText: '#000000',
+};
diff --git a/src/Theme/index.js b/src/Theme/index.js
new file mode 100644
index 0000000..16d31f9
--- /dev/null
+++ b/src/Theme/index.js
@@ -0,0 +1 @@
+export {ThemeProvider, useTheme, lightColors, darkColors} from './ThemeContext';
From 7051a7a92fdac48358805ca8f41885dbd8e0478d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 25 Nov 2025 11:06:27 +0000
Subject: [PATCH 3/3] fix: Address code review feedback - use theme colors for
links
Co-authored-by: pushpender-singh-ap <73298854+pushpender-singh-ap@users.noreply.github.com>
---
src/Screens/Settings/index.js | 4 ++--
src/Theme/colors.js | 8 +++++++-
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/Screens/Settings/index.js b/src/Screens/Settings/index.js
index 7e17653..c085071 100644
--- a/src/Screens/Settings/index.js
+++ b/src/Screens/Settings/index.js
@@ -147,7 +147,7 @@ export function Settings({navigation}) {
{getThemeModeLabel(themeMode)}
@@ -344,7 +344,7 @@ export function Settings({navigation}) {
{scrollPreference === 'horizontal' ? 'Horizontal' : 'Vertical'}
diff --git a/src/Theme/colors.js b/src/Theme/colors.js
index 110bc48..e222f70 100644
--- a/src/Theme/colors.js
+++ b/src/Theme/colors.js
@@ -57,8 +57,11 @@ export const lightColors = {
iconSecondary: '#666666',
// Settings specific
- settingsItem: '#FFFFFF',
+ settingsItem: '#F5F5F5',
settingsItemText: '#000000',
+
+ // Link and action colors
+ link: '#007AFF',
};
export const darkColors = {
@@ -117,4 +120,7 @@ export const darkColors = {
// Settings specific
settingsItem: '#FFFFFF',
settingsItemText: '#000000',
+
+ // Link and action colors
+ link: '#007AFF',
};