выдает ошибку property colors doesnt exist. Исправь. просто сделай нормальный код. Я не программист и не умею писать код, так что не ленись, покажи код без сокращений а-ля "пиши сам, я даю только идеи!"
покажи без сокражений. Полностью. От начала до конца весь код, буквально каждый символ покажи, ничего не оставляй мне, потому что я не умею псиать код
покажи исправленный код от начала до конца. Не оставляй части кода на потом, пиши сразу всё
ХВАТИТ ГОВОРИТЬ "ЗДЕСЬ ЧТО-ТО БУДЕТ", СДЕЛАЙ ЭТО БЕЗ ХАЛТУРЫ В ВИДЕ КОММЕНТАРИЕВ, СДЕЛАЙ ПОЛНОЦЕННЫЙ КОД!!!!
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/android/build.gradle
File: build.gradle
buildscript {
ext {
buildToolsVersion = "34.0.0"
minSdkVersion = 23
compileSdkVersion = 34
targetSdkVersion = 34
ndkVersion = "26.1.10909125"
kotlinVersion = "1.9.24"
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
}
}
apply plugin: "com.facebook.react.rootproject"
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/android/app/build.gradle
File: build.gradle
apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
/**
* This is the configuration block to customize your React Native Android app.
* By default you don't need to apply any configuration, just uncomment the lines you need.
*/
react {
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '../..'
// root = file("../../")
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
// reactNativeDir = file("../../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
// codegenDir = file("../../node_modules/@react-native/codegen")
// The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js
// cliFile = file("../../node_modules/react-native/cli.js")
/* Variants */
// The list of variants to that are debuggable. For those we're going to
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
// debuggableVariants = ["liteDebug", "prodDebug"]
/* Bundling */
// A list containing the node command and its flags. Default is just 'node'.
// nodeExecutableAndArgs = ["node"]
//
// The command to run when bundling. By default is 'bundle'
// bundleCommand = "ram-bundle"
//
// The path to the CLI configuration file. Default is empty.
// bundleConfig = file(../rn-cli.config.js)
//
// The name of the generated asset file containing your JS bundle
// bundleAssetName = "MyApplication.android.bundle"
//
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
// entryFile = file("../js/MyApplication.android.js")
//
// A list of extra flags to pass to the 'bundle' commands.
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
// extraPackagerArgs = []
/* Hermes Commands */
// The hermes compiler command to run. By default it is 'hermesc'
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
//
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"]
/* Autolinking */
autolinkLibrariesWithApp()
}
/**
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
*/
def enableProguardInReleaseBuilds = false
/**
* The preferred build flavor of JavaScriptCore (JSC)
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
android {
ndkVersion rootProject.ext.ndkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion
namespace "com.arsennikiforovcli"
defaultConfig {
applicationId "com.arsennikiforovcli"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
}
dependencies {
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android")
} else {
implementation jscFlavor
}
}
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/android/settings.gradle
File: settings.gradle
pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
rootProject.name = 'arsenNikiforovCLI'
include ':app'
includeBuild('../node_modules/@react-native/gradle-plugin')
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/App.js
File: App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Provider } from 'react-redux';
import { ThemeProvider } from './ThemeContext';
import store from './store/store';
import Home from './screens/Home';
import Lab1 from './screens/Lab1';
import Lab2 from './screens/Lab2';
import Lab3 from './screens/Lab3';
import Lab4 from './screens/Lab4';
const Stack = createNativeStackNavigator();
const App = () => {
return (
<Provider store={store}>
<ThemeProvider>
<NavigationContainer>
<Stack.Navigator initialRouteName="Home" screenOptions={{ headerShown: false }}>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Lab1" component={Lab1} />
<Stack.Screen name="Lab2" component={Lab2} />
<Stack.Screen name="Lab3" component={Lab3} />
<Stack.Screen name="Lab4" component={Lab4} />
</Stack.Navigator>
</NavigationContainer>
</ThemeProvider>
</Provider>
);
};
export default App;
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/screens/Home.js
File: Home.js
// Home.js
import React, { useContext } from 'react';
import { View, TouchableOpacity, StyleSheet, Dimensions } from 'react-native';
import { ThemeContext } from '../ThemeContext';
import ThemedBackground from '../components/ThemedBackground';
import ThemedText from '../components/ThemedText';
const { width } = Dimensions.get('window');
const Home = ({ navigation }) => {
const { colors } = useContext(ThemeContext);
const handleNavigation = (screen) => {
navigation.navigate(screen);
};
const menuItems = [
{ screen: 'Lab1', text: 'Bubble Game', icon: '🎮' },
{ screen: 'Lab2', text: 'NASA API', icon: '🚀' },
{ screen: 'Lab3', text: 'Space Calculator', icon: '🧮' },
{ screen: 'Lab4', text: 'Redux Theme', icon: '⚙️' },
];
return (
<ThemedBackground>
<View style={styles.container}>
<View style={[styles.card, { backgroundColor: colors.card, shadowColor: colors.shadow }]}>
<ThemedText style={styles.title}>CyberLabs 2077</ThemedText>
<ThemedText style={styles.subtitle}>Лабораторные работы</ThemedText>
<View style={styles.studentInfo}>
<ThemedText style={styles.studentText}>Студент: Никифоров Арсен</ThemedText>
<ThemedText style={styles.studentText}>Группа: ФИИТ-21</ThemedText>
</View>
<ThemedText style={styles.selectionText}>Выберите экран:</ThemedText>
<View style={styles.menuContainer}>
{menuItems.map(({ screen, text, icon }) => (
<TouchableOpacity
key={screen}
onPress={() => handleNavigation(screen)}
style={[
styles.menuItem,
{
backgroundColor: colors.secondary,
borderColor: colors.border,
shadowColor: colors.shadow,
},
]}
>
<View style={styles.menuItemContent}>
<ThemedText style={styles.icon}>{icon}</ThemedText>
<ThemedText style={styles.menuText}>{text}</ThemedText>
</View>
</TouchableOpacity>
))}
</View>
</View>
</View>
</ThemedBackground>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
paddingTop: 60,
},
card: {
width: width * 0.9,
padding: 20,
borderRadius: 15,
alignItems: 'center',
elevation: 5,
shadowOffset: { width: 0, height: 3 },
shadowOpacity: 0.2,
shadowRadius: 4,
},
title: {
fontSize: 34,
fontWeight: 'bold',
marginBottom: 10,
color: '#7289DA',
},
subtitle: {
fontSize: 22,
marginBottom: 15,
},
studentInfo: {
marginBottom: 15,
alignItems: 'center',
},
studentText: {
fontSize: 18,
marginBottom: 2,
},
selectionText: {
fontSize: 18,
marginBottom: 15,
},
menuContainer: {
width: '100%',
},
menuItem: {
width: '100%',
paddingVertical: 15,
paddingHorizontal: 20,
borderRadius: 12,
marginBottom: 10,
borderWidth: 1,
elevation: 3,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 3,
},
menuItemContent: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
icon: {
fontSize: 24,
marginRight: 12,
},
menuText: {
fontSize: 18,
},
});
export default Home;
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/screens/lab1.js
File: lab1.js
import React, { useState, useEffect, useContext } from 'react';
import {
View,
TouchableOpacity,
Modal,
StyleSheet,
Dimensions,
TouchableWithoutFeedback,
} from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import ThemedBackground from '../components/ThemedBackground';
import ThemedText from '../components/ThemedText';
import Bubble from '../components/Bubble';
import { ThemeContext } from '../ThemeContext';
import { incrementCounter } from '../store/store';
const { width, height } = Dimensions.get('window');
const Lab1 = () => {
const [bubbles, setBubbles] = useState([]);
const [score, setScore] = useState(0);
const [gameOver, setGameOver] = useState(false);
const [modalVisible, setModalVisible] = useState(false);
const counter = useSelector((state) => state.counter);
const dispatch = useDispatch();
const { colors } = useContext(ThemeContext);
if (!colors) {
console.error('ThemeContext не предоставляет colors!');
return null;
}
const addBubble = () => {
const id = Date.now() + Math.random();
setBubbles((prev) => [...prev, { id }]);
};
const removeBubble = (id) => {
setBubbles((prev) => prev.filter((bubble) => bubble.id !== id));
};
const onBubblePress = () => {
setScore((prev) => prev + 5);
dispatch(incrementCounter());
};
useEffect(() => {
if (!gameOver) {
const interval = setInterval(addBubble, 2000);
return () => clearInterval(interval);
}
}, [gameOver]);
useEffect(() => {
const timer = setTimeout(() => {
setGameOver(true);
}, 20000);
return () => clearTimeout(timer);
}, []);
const resetGame = () => {
setBubbles([]);
setScore(0);
setGameOver(false);
};
return (
<ThemedBackground>
<View style={styles.header}>
<TouchableOpacity
style={[styles.infoButton, { backgroundColor: colors.accent }]}
onPress={() => setModalVisible(true)}
>
<ThemedText style={styles.infoButtonText}>Info</ThemedText>
</TouchableOpacity>
<ThemedText style={styles.scoreText}>Score: {score}</ThemedText>
<ThemedText style={styles.counterText}>Counter: {counter}</ThemedText>
</View>
<TouchableWithoutFeedback onPress={addBubble}>
<View style={styles.touchableArea}>
{bubbles.map((bubble) => (
<Bubble
key={bubble.id}
id={bubble.id}
removeBubble={removeBubble}
onBubblePress={onBubblePress}
gameOver={gameOver}
/>
))}
</View>
</TouchableWithoutFeedback>
<Modal transparent visible={modalVisible} animationType="fade">
<View style={styles.modalBackground}>
<View style={[styles.modalContainer, { backgroundColor: colors.card }]}>
<ThemedText style={styles.modalTitle}>Как играть</ThemedText>
<ThemedText style={styles.modalText}>Нажимайте на пузырьки, чтобы заработать очки!</ThemedText>
<TouchableOpacity
style={[styles.closeButton, { backgroundColor: colors.accent }]}
onPress={() => setModalVisible(false)}
>
<ThemedText style={styles.closeButtonText}>Закрыть</ThemedText>
</TouchableOpacity>
</View>
</View>
</Modal>
{gameOver && (
<View style={[styles.gameOverContainer, { backgroundColor: colors.card }]}>
<ThemedText style={styles.gameOverText}>Игра окончена!</ThemedText>
<ThemedText style={styles.finalScoreText}>Ваш счёт: {score}</ThemedText>
<TouchableOpacity
style={[styles.restartButton, { backgroundColor: colors.accent }]}
onPress={resetGame}
>
<ThemedText style={styles.restartButtonText}>Играть снова</ThemedText>
</TouchableOpacity>
</View>
)}
</ThemedBackground>
);
};
const styles = StyleSheet.create({
header: {
position: 'absolute',
top: 40,
width: '100%',
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 20,
zIndex: 1,
},
infoButton: {
padding: 10,
borderRadius: 8,
elevation: 3,
},
infoButtonText: {
fontSize: 16,
fontWeight: '600',
},
scoreText: {
fontSize: 18,
fontWeight: '500',
},
counterText: {
fontSize: 18,
fontWeight: '500',
},
touchableArea: {
flex: 1,
},
modalBackground: {
flex: 1,
backgroundColor: colors.shadow,
justifyContent: 'center',
alignItems: 'center',
},
modalContainer: {
width: width * 0.8,
padding: 20,
borderRadius: 15,
alignItems: 'center',
elevation: 5,
},
modalTitle: {
fontSize: 22,
fontWeight: '700',
marginBottom: 10,
},
modalText: {
fontSize: 16,
textAlign: 'center',
marginBottom: 20,
},
closeButton: {
padding: 12,
borderRadius: 8,
},
closeButtonText: {
fontSize: 16,
fontWeight: '600',
},
gameOverContainer: {
position: 'absolute',
top: height / 3,
left: width * 0.1,
right: width * 0.1,
padding: 20,
borderRadius: 15,
alignItems: 'center',
elevation: 5,
},
gameOverText: {
fontSize: 24,
fontWeight: '700',
marginBottom: 10,
},
finalScoreText: {
fontSize: 18,
marginBottom: 20,
},
restartButton: {
padding: 12,
borderRadius: 8,
},
restartButtonText: {
fontSize: 16,
fontWeight: '600',
},
});
export default Lab1;
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/screens/lab2.js
File: lab2.js
// Lab2.js
import React, { useState, useEffect, useCallback, useMemo, useReducer, createContext, useContext } from 'react';
import {
View,
StyleSheet,
TouchableOpacity,
Image,
ScrollView,
ActivityIndicator,
Alert,
Text,
Dimensions,
} from 'react-native';
import WebView from 'react-native-webview';
import { ThemeContext } from '../ThemeContext';
const { width, height } = Dimensions.get('window');
const GlobalStateContext = createContext();
const initialState = {
data: null,
loading: false,
error: null,
};
const dataReducer = (state, action) => {
switch (action.type) {
case 'FETCH_INIT':
return { ...state, loading: true, error: null };
case 'FETCH_SUCCESS':
return { data: action.payload, loading: false, error: null };
case 'FETCH_FAILURE':
return { ...state, loading: false, error: action.payload };
default:
throw new Error();
}
};
const useAPOD = (date) => {
const [state, dispatch] = useReducer(dataReducer, initialState);
const fetchData = useCallback(async () => {
dispatch({ type: 'FETCH_INIT' });
try {
const response = await fetch(
`https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&date=${date}`
);
if (!response.ok) {
throw new Error(`Network response was not ok: ${response.statusText}`);
}
const result = await response.json();
dispatch({ type: 'FETCH_SUCCESS', payload: result });
} catch (error) {
dispatch({ type: 'FETCH_FAILURE', payload: error.message });
}
}, [date]);
useEffect(() => {
fetchData();
}, [fetchData]);
return state;
};
const VideoPlayer = ({ url }) => {
const getYoutubeVideoId = (url) => {
const regExp =
/^.*(youtu.be\/|v\/|u\/w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
const match = url.match(regExp);
return match && match[2].length === 11 ? match[2] : null;
};
const videoId = getYoutubeVideoId(url);
const embedUrl = videoId
? `https://www.youtube.com/embed/${videoId}`
: url;
return (
<View style={styles.videoWrapper}>
<WebView
source={{ uri: embedUrl }}
style={styles.video}
allowsFullscreenVideo={true}
mediaPlaybackRequiresUserAction={false}
/>
</View>
);
};
const Lab2 = ({ navigation }) => {
const [date, setDate] = useState(() => {
return new Date().toISOString().slice(0, 10);
});
const { data, loading, error } = useAPOD(date);
const { globalData, setGlobalData } = useContext(GlobalStateContext);
const { colors } = useContext(ThemeContext);
const loadRandomAPOD = useCallback(() => {
const randomDate = new Date(
Date.now() - Math.floor(Math.random() * 1000 * 60 * 60 * 24 * 365)
)
.toISOString()
.slice(0, 10);
setDate(randomDate);
}, []);
const memoizedData = useMemo(() => data, [data]);
const updateGlobalData = useCallback(() => {
if (memoizedData) {
setGlobalData(memoizedData);
Alert.alert('Успешно', 'Изображение сохранено в избранное!');
}
}, [memoizedData, setGlobalData]);
const styles = StyleSheet.create({
container: {
flex: 1,
width,
height,
resizeMode: 'cover',
backgroundColor: colors.background,
},
header: {
marginTop: 40,
alignItems: 'flex-end',
marginRight: 20,
},
button: {
padding: 15,
borderRadius: 8,
borderWidth: 1.5,
backgroundColor: colors.accent,
},
buttonText: {
fontSize: 16,
color: colors.text,
},
content: {
alignItems: 'center',
padding: 20,
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
loadingText: {
fontSize: 18,
color: colors.text,
},
errorContainer: {
alignItems: 'center',
marginTop: 20,
},
errorText: {
fontSize: 18,
color: 'red',
},
retryButton: {
marginTop: 10,
padding: 10,
borderRadius: 8,
backgroundColor: colors.accent,
},
retryButtonText: {
fontSize: 16,
color: colors.text,
},
dataContainer: {
alignItems: 'center',
},
titleText: {
fontSize: 22,
marginBottom: 10,
fontWeight: 'bold',
color: colors.text,
},
image: {
width: width - 40,
height: 300,
borderRadius: 10,
},
videoWrapper: {
width: width - 40,
height: 300,
borderRadius: 10,
overflow: 'hidden',
},
video: {
width: '100%',
height: '100%',
},
dateText: {
fontSize: 16,
marginVertical: 10,
color: colors.text,
},
explanationText: {
fontSize: 14,
textAlign: 'center',
marginTop: 10,
color: colors.text,
},
globalButton: {
padding: 12,
borderRadius: 8,
marginTop: 15,
backgroundColor: colors.accent,
},
globalButtonText: {
fontSize: 16,
color: colors.text,
},
savedDataContainer: {
marginTop: 30,
padding: 20,
borderRadius: 10,
backgroundColor: colors.secondary,
},
savedDataTitle: {
fontSize: 18,
color: colors.text,
},
savedDataText: {
fontSize: 14,
color: colors.text,
},
viewSavedButton: {
marginTop: 10,
padding: 10,
borderRadius: 8,
backgroundColor: colors.accent,
},
viewSavedButtonText: {
fontSize: 16,
color: colors.text,
},
videoContainer: {
width: width - 40,
height: 200,
justifyContent: 'center',
alignItems: 'center',
},
videoText: {
fontSize: 16,
textAlign: 'center',
color: colors.text,
},
});
return (
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity
style={styles.button}
onPress={loadRandomAPOD}
>
<Text style={styles.buttonText}>
Загрузить другое изображение
</Text>
</TouchableOpacity>
</View>
<ScrollView contentContainerStyle={styles.content}>
{loading ? (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color={colors.accent} />
<Text style={styles.loadingText}>Загрузка данных...</Text>
</View>
) : error ? (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>Ошибка: {error}</Text>
<TouchableOpacity
style={styles.retryButton}
onPress={loadRandomAPOD}
>
<Text style={styles.retryButtonText}>Повторить</Text>
</TouchableOpacity>
</View>
) : memoizedData ? (
<View style={styles.dataContainer}>
<Text style={styles.titleText}>
{memoizedData.title || 'Название недоступно'}
</Text>
{memoizedData.media_type === 'image' ? (
<Image
source={{ uri: memoizedData.url }}
style={styles.image}
resizeMode="contain"
/>
) : memoizedData.media_type === 'video' ? (
<VideoPlayer url={memoizedData.url} />
) : (
<View style={styles.videoContainer}>
<Text style={styles.videoText}>
Формат медиа не поддерживается
</Text>
</View>
)}
<Text style={styles.dateText}>
Дата: {memoizedData.date}
</Text>
<Text style={styles.explanationText}>
{memoizedData.explanation}
</Text>
<TouchableOpacity
style={styles.globalButton}
onPress={updateGlobalData}
>
<Text style={styles.globalButtonText}>
Сохранить в избранное
</Text>
</TouchableOpacity>
</View>
) : (
<Text style={styles.errorText}>
Данные не загружены
</Text>
)}
{globalData && (
<View style={styles.savedDataContainer}>
<Text style={styles.savedDataTitle}>
Сохраненное изображение:
</Text>
<Text style={styles.savedDataText}>
{globalData.title}
</Text>
<Text style={styles.savedDataText}>
Дата: {globalData.date}
</Text>
<TouchableOpacity
style={styles.viewSavedButton}
onPress={() =>
navigation.navigate('SavedImage', { data: globalData })
}
>
<Text style={styles.viewSavedButtonText}>
Просмотреть
</Text>
</TouchableOpacity>
</View>
)}
</ScrollView>
</View>
);
};
const GlobalStateProvider = ({ children }) => {
const [globalData, setGlobalData] = useState(null);
return (
<GlobalStateContext.Provider value={{ globalData, setGlobalData }}>
{children}
</GlobalStateContext.Provider>
);
};
const Lab2WithProvider = (props) => (
<GlobalStateProvider>
<Lab2 {...props} />
</GlobalStateProvider>
);
export default Lab2WithProvider;
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/screens/lab3.js
File: lab3.js
// Lab3.js
import React, { useState, useMemo, useCallback, useContext } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
ImageBackground,
Animated,
Dimensions,
} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { ThemeContext } from '../ThemeContext';
const { width, height } = Dimensions.get('window');
const OPERATIONS = ['+', '-', '*', '/'];
const MAX_LEVEL = 5;
const MAX_MISTAKES = 3;
const Lab3 = () => {
const [level, setLevel] = useState(1);
const [score, setScore] = useState(0);
const [gameOver, setGameOver] = useState(false);
const [currentProblem, setCurrentProblem] = useState(null);
const [userAnswer, setUserAnswer] = useState('');
const [mistakes, setMistakes] = useState(0);
const [shakeAnimation] = useState(new Animated.Value(0));
const { colors } = useContext(ThemeContext);
const generateProblem = useCallback(level => {
const operation = OPERATIONS[Math.floor(Math.random() * OPERATIONS.length)];
let num1, num2;
switch (operation) {
case '+':
num1 = Math.floor(Math.random() * (20 * level)) + 1;
num2 = Math.floor(Math.random() * (20 * level)) + 1;
break;
case '-':
num1 = Math.floor(Math.random() * (20 * level)) + 1;
num2 = Math.floor(Math.random() * num1) + 1;
break;
case '*':
num1 = Math.floor(Math.random() * (10 * level)) + 1;
num2 = Math.floor(Math.random() * (10 * level)) + 1;
break;
case '/':
num2 = Math.floor(Math.random() * (10 * level)) + 1;
num1 = num2 * (Math.floor(Math.random() * (10 * level)) + 1);
break;
}
return { num1, num2, operation };
}, []);
const calculateAnswer = useCallback(problem => {
const { num1, num2, operation } = problem;
switch (operation) {
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
case '/':
return num1 / num2;
}
}, []);
const memoizedProblem = useMemo(() => {
if (!currentProblem) {
const newProblem = generateProblem(level);
setCurrentProblem(newProblem);
return newProblem;
}
return currentProblem;
}, [level, currentProblem, generateProblem]);
const memoizedAnswer = useMemo(() => {
return calculateAnswer(memoizedProblem);
}, [memoizedProblem, calculateAnswer]);
const checkAnswer = useCallback(() => {
const userAnswerNum = parseFloat(userAnswer);
if (Math.abs(userAnswerNum - memoizedAnswer) < 0.01) {
ReactNativeHapticFeedback.trigger('notificationSuccess');
setScore(score + level * 10);
if (level < MAX_LEVEL) {
setLevel(level + 1);
} else {
setGameOver(true);
}
setCurrentProblem(null);
} else {
ReactNativeHapticFeedback.trigger('notificationError');
setMistakes(mistakes + 1);
if (mistakes + 1 >= MAX_MISTAKES) {
setGameOver(true);
}
Animated.sequence([
Animated.timing(shakeAnimation, {
toValue: 10,
duration: 100,
useNativeDriver: true,
}),
Animated.timing(shakeAnimation, {
toValue: -10,
duration: 100,
useNativeDriver: true,
}),
Animated.timing(shakeAnimation, {
toValue: 10,
duration: 100,
useNativeDriver: true,
}),
Animated.timing(shakeAnimation, {
toValue: 0,
duration: 100,
useNativeDriver: true,
}),
]).start();
}
setUserAnswer('');
}, [
userAnswer,
memoizedAnswer,
level,
score,
mistakes,
shakeAnimation,
]);
const restartGame = useCallback(() => {
setLevel(1);
setScore(0);
setGameOver(false);
setCurrentProblem(null);
setUserAnswer('');
setMistakes(0);
}, []);
const renderKeypad = useCallback(() => {
const keys = [
['7', '8', '9'],
['4', '5', '6'],
['1', '2', '3'],
['.', '0', '⌫'],
];
return keys.map((row, rowIndex) => (
<View key={`row-${rowIndex}`} style={styles.keypadRow}>
{row.map(key => (
<TouchableOpacity
key={key}
style={styles.keypadButton}
onPress={() => {
ReactNativeHapticFeedback.trigger('selection');
if (key === '⌫') {
setUserAnswer(userAnswer.slice(0, -1));
} else if (userAnswer.length < 8) {
setUserAnswer(userAnswer + key);
}
}}
>
<Text style={styles.keypadButtonText}>{key}</Text>
</TouchableOpacity>
))}
</View>
));
}, [userAnswer, colors]);
const styles = StyleSheet.create({
container: {
flex: 1,
width,
height,
resizeMode: 'cover',
},
gradient: {
flex: 1,
padding: 20,
backgroundColor: colors.background,
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 20,
},
levelText: {
fontSize: 24,
fontWeight: 'bold',
color: colors.primary,
},
scoreText: {
fontSize: 24,
fontWeight: 'bold',
color: colors.primary,
},
mistakesText: {
fontSize: 24,
fontWeight: 'bold',
color: colors.primary,
},
problemContainer: {
backgroundColor: 'rgba(0, 0, 0, 0.6)',
padding: 20,
borderRadius: 10,
marginBottom: 20,
alignItems: 'center',
},
problemText: {
fontSize: 32,
textAlign: 'center',
color: colors.text,
},
answerContainer: {
backgroundColor: 'rgba(255, 255, 255, 0.2)',
padding: 10,
borderRadius: 5,
marginBottom: 20,
minWidth: 150,
alignItems: 'center',
},
answerText: {
fontSize: 28,
color: colors.text,
},
keypadContainer: {
justifyContent: 'center',
alignItems: 'center',
marginBottom: 20,
},
keypadRow: {
flexDirection: 'row',
justifyContent: 'center',
},
keypadButton: {
width: 70,
height: 70,
justifyContent: 'center',
alignItems: 'center',
margin: 5,
borderRadius: 10,
borderWidth: 1.5,
backgroundColor: colors.secondary,
borderColor: colors.primary,
},
keypadButtonText: {
fontSize: 24,
color: colors.primary,
},
submitButton: {
padding: 15,
borderRadius: 10,
alignSelf: 'center',
width: '80%',
alignItems: 'center',
backgroundColor: colors.accent,
},
submitButtonText: {
fontSize: 24,
color: colors.text,
},
gameOverContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
gameOverText: {
fontSize: 36,
marginBottom: 20,
textAlign: 'center',
color: colors.text,
},
finalScoreText: {
fontSize: 28,
marginBottom: 20,
color: colors.text,
},
restartButton: {
padding: 15,
borderRadius: 10,
backgroundColor: colors.accent,
},
restartButtonText: {
fontSize: 24,
color: colors.text,
},
});
if (gameOver) {
return (
<ImageBackground
source={
mistakes >= MAX_MISTAKES
? require('../assets/space_defeat.jpg')
: require('../assets/space_victory.jpg')
}
style={styles.container}
>
<LinearGradient
colors={[colors.background, colors.background]}
style={styles.gradient}
>
<View style={styles.gameOverContainer}>
<Text style={styles.gameOverText}>
{mistakes >= MAX_MISTAKES
? 'The Galaxy has been conquered!'
: 'The Galaxy has been saved!'}
</Text>
<Text style={styles.finalScoreText}>
Final Score: {score}
</Text>
<TouchableOpacity
style={styles.restartButton}
onPress={restartGame}
>
<Text style={styles.restartButtonText}>
Start New Mission
</Text>
</TouchableOpacity>
</View>
</LinearGradient>
</ImageBackground>
);
}
return (
<ImageBackground
source={require('../assets/space_background.jpg')}
style={styles.container}
>
<LinearGradient
colors={[colors.background, colors.background]}
style={styles.gradient}
>
<View style={styles.header}>
<Text style={styles.levelText}>Level: {level}</Text>
<Text style={styles.scoreText}>Score: {score}</Text>
<Text style={styles.mistakesText}>
Mistakes: {mistakes}/{MAX_MISTAKES}
</Text>
</View>
<View style={styles.problemContainer}>
<Animated.Text
style={[
styles.problemText,
{ transform: [{ translateX: shakeAnimation }] },
]}
>
{`${memoizedProblem.num1} ${memoizedProblem.operation} ${memoizedProblem.num2} = ?`}
</Animated.Text>
</View>
<View style={styles.answerContainer}>
<Text style={styles.answerText}>{userAnswer}</Text>
</View>
<View style={styles.keypadContainer}>{renderKeypad()}</View>
<TouchableOpacity
style={styles.submitButton}
onPress={checkAnswer}
>
<Text style={styles.submitButtonText}>
Destroy Invaders
</Text>
</TouchableOpacity>
</LinearGradient>
</ImageBackground>
);
};
export default Lab3;
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/screens/lab4.js
File: lab4.js
// Lab4.js
import React, { useEffect, useContext } from 'react';
import { View, TouchableOpacity, StyleSheet, Switch, Text } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import { incrementCounter, decrementCounter } from '../store/store';
import { ThemeContext } from '../ThemeContext';
const Lab4 = ({ navigation }) => {
const counter = useSelector(state => state.counter);
const dispatch = useDispatch();
const { theme, toggleTheme, colors } = useContext(ThemeContext);
useEffect(() => {
console.log('Counter updated:', counter);
}, [counter]);
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 20,
backgroundColor: colors.background,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 16,
color: colors.text,
},
text: {
fontSize: 16,
marginBottom: 16,
color: colors.text,
},
switch: {
marginBottom: 24,
},
counterContainer: {
alignItems: 'center',
marginBottom: 24,
},
counterText: {
fontSize: 20,
marginBottom: 16,
fontWeight: 'bold',
color: colors.text,
},
buttonContainer: {
flexDirection: 'row',
},
button: {
padding: 12,
marginHorizontal: 8,
borderRadius: 50,
width: 120,
alignItems: 'center',
backgroundColor: colors.accent,
},
buttonText: {
fontSize: 16,
fontWeight: 'bold',
color: colors.text,
},
navigationButtonsContainer: {
alignItems: 'center',
marginTop: 24,
},
navigationButton: {
padding: 12,
borderRadius: 24,
alignItems: 'center',
width: 200,
marginVertical: 8,
backgroundColor: colors.accent,
},
});
return (
<View style={styles.container}>
<Text style={styles.title}>Redux Theme Switcher</Text>
<Text style={styles.text}>
Current theme: {theme === 'light' ? 'Light' : 'Dark'}
</Text>
<Switch
value={theme === 'dark'}
onValueChange={toggleTheme}
thumbColor={colors.accent}
trackColor={{ false: colors.secondary, true: colors.primary }}
style={styles.switch}
/>
<View style={styles.counterContainer}>
<Text style={styles.counterText}>
Redux Counter: {counter}
</Text>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.button}
onPress={() => dispatch(incrementCounter())}
>
<Text style={styles.buttonText}>Increment</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => dispatch(decrementCounter())}
>
<Text style={styles.buttonText}>Decrement</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.navigationButtonsContainer}>
<TouchableOpacity
style={styles.navigationButton}
onPress={() => navigation.navigate('Lab1')}
>
<Text style={styles.buttonText}>Go to Lab 1</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navigationButton}
onPress={() => navigation.navigate('Lab2')}
>
<Text style={styles.buttonText}>Go to Lab 2</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.navigationButton}
onPress={() => navigation.navigate('Lab3')}
>
<Text style={styles.buttonText}>Go to Lab 3</Text>
</TouchableOpacity>
</View>
</View>
);
};
export default Lab4;
Файл не найден: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024\arsenNikiforovCLI/SavedImage.js
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/package.json
File: package.json
{
"name": "arsenNikiforovCLI",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"lint": "eslint .",
"start": "react-native start",
"test": "jest"
},
"dependencies": {
"@react-navigation/native": "^6.1.18",
"@react-navigation/native-stack": "^6.11.0",
"@react-navigation/stack": "^6.4.1",
"expo-haptics": "^13.0.1",
"expo-linear-gradient": "^13.0.2",
"react": "18.3.1",
"react-native": "0.75.4",
"react-native-gesture-handler": "^2.20.0",
"react-native-haptic-feedback": "^2.3.3",
"react-native-linear-gradient": "^2.8.3",
"react-native-safe-area-context": "^4.11.0",
"react-native-screens": "^3.34.0",
"react-native-svg": "^15.7.1",
"react-native-webview": "^13.12.3",
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"zustand": "^5.0.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@babel/preset-env": "^7.20.0",
"@babel/runtime": "^7.20.0",
"@react-native-community/cli": "latest",
"@react-native/babel-preset": "0.75.4",
"@react-native/eslint-config": "0.75.4",
"@react-native/metro-config": "0.75.4",
"@react-native/typescript-config": "0.75.4",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.6.3",
"eslint": "^8.19.0",
"jest": "^29.6.3",
"prettier": "2.8.8",
"react-test-renderer": "18.3.1"
},
"engines": {
"node": ">=18"
}
}
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/index.js
File: index.js
import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
import React from 'react';
import { Provider } from 'react-redux';
import store from './store/store';
const ReduxApp = () => (
<Provider store={store}>
<App />
</Provider>
);
AppRegistry.registerComponent(appName, () => ReduxApp);
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/components/ThemedBackground.js
File: ThemedBackground.js
import React, { useContext } from 'react';
import { View, StyleSheet } from 'react-native';
import { ThemeContext } from '../ThemeContext';
const ThemedBackground = ({ children, style }) => {
const context = useContext(ThemeContext);
if (!context || !context.colors) {
console.error('ThemeContext не предоставляет colors!');
return null;
}
const { colors } = context;
return (
<View style={[styles.container, { backgroundColor: colors.background }, style]}>
{children}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default ThemedBackground;
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/components/ThemedText.js
File: ThemedText.js
import React, { createContext, useState } from 'react';
export const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme] = useState({
colors: {
accent: '#3498db',
card: '#ffffff',
shadow: 'rgba(0, 0, 0, 0.5)',
background: '#f5f5f5',
},
});
return (
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
);
};
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/store/store.js
File: store.js
// store.js
import { createStore } from 'redux';
const initialState = {
counter: 0,
};
export const incrementCounter = () => ({
type: 'INCREMENT_COUNTER',
});
export const decrementCounter = () => ({
type: 'DECREMENT_COUNTER',
});
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT_COUNTER':
return { ...state, counter: state.counter + 1 };
case 'DECREMENT_COUNTER':
return { ...state, counter: state.counter - 1 };
default:
return state;
}
};
const store = createStore(reducer);
export default store;
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/android/gradle.properties
File: gradle.properties
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Use this property to specify which architecture you want to build.
# You can also override it from the CLI using
# ./gradlew <task> -PreactNativeArchitectures=x86_64
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# Use this property to enable support to the new architecture.
# This will allow you to use TurboModules and the Fabric render in
# your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
newArchEnabled=false
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
hermesEnabled=true
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/android/gradle/wrapper/gradle-wrapper.properties
File: gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI/app.json
File: app.json
{
"name": "arsenNikiforovCLI",
"displayName": "arsenNikiforovCLI"
}
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLIFile: Bubble.js
// Bubble.js
import React, { useEffect, useState, useContext } from 'react';
import { Animated, StyleSheet, Dimensions, TouchableWithoutFeedback } from 'react-native';
import { ThemeContext } from '../ThemeContext';
const { width, height } = Dimensions.get('window');
const Bubble = ({ id, removeBubble, onBubblePress, gameOver }) => {
const [position] = useState(
new Animated.ValueXY({ x: Math.random() * (width - 60), y: height })
);
const [opacity] = useState(new Animated.Value(1));
const { colors } = useContext(ThemeContext);
if (!colors) {
console.error('ThemeContext не предоставляет colors');
return null;
}
useEffect(() => {
if (!gameOver) {
Animated.timing(position, {
toValue: { x: position.x._value, y: -100 },
duration: 5000,
useNativeDriver: true,
}).start(({ finished }) => {
if (finished) {
removeBubble(id);
}
});
} else {
Animated.timing(opacity, {
toValue: 0,
duration: 500,
useNativeDriver: true,
}).start();
}
}, [gameOver]);
const handlePress = () => {
Animated.timing(opacity, {
toValue: 0,
duration: 200,
useNativeDriver: true,
}).start(() => {
removeBubble(id);
onBubblePress();
});
};
return (
<TouchableWithoutFeedback onPress={handlePress}>
<Animated.View
style={[
styles.bubble,
{
backgroundColor: colors.accent,
transform: position.getTranslateTransform(),
opacity,
shadowColor: colors.shadow,
},
]}
/>
</TouchableWithoutFeedback>
);
};
const styles = StyleSheet.create({
bubble: {
position: 'absolute',
width: 60,
height: 60,
borderRadius: 30,
elevation: 3,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 3,
},
});
export default Bubble;
Full path: C:\Users\Arsenshmid\Desktop\AndroidArsen\mobile-develop-2024rsenNikiforovCLI\ThemeContext.js
File: ThemeContext.js
// ThemeContext.js
import React, { createContext, useState } from 'react';
export const ThemeContext = createContext();
const lightTheme = {
background: '#F3F4F6',
text: '#2E3338',
primary: '#7289DA',
secondary: '#FFFFFF',
accent: '#5865F2',
card: '#FFFFFF',
border: '#D1D5DB',
shadow: 'rgba(0, 0, 0, 0.1)',
};
const darkTheme = {
background: '#36393F',
text: '#FFFFFF',
primary: '#7289DA',
secondary: '#2F3136',
accent: '#5865F2',
card: '#2F3136',
border: '#202225',
shadow: 'rgba(0, 0, 0, 0.7)',
};
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light'); // Светлая тема по умолчанию
const toggleTheme = () => {
setTheme((prev) => (prev === 'light' ? 'dark' : 'light'));
};
const colors = theme === 'light' ? lightTheme : darkTheme;
return (
<ThemeContext.Provider value={{ theme, toggleTheme, colors }}>
{children}
</ThemeContext.Provider>
);
};