Compare commits

..

No commits in common. "master" and "lab5" have entirely different histories.
master ... lab5

22 changed files with 378 additions and 166 deletions

View File

@ -1,4 +1,4 @@
# mobilefl
# identity
A new Flutter project.

View File

@ -6,7 +6,7 @@ plugins {
}
android {
namespace = "com.example.mobilefl"
namespace = "com.example.identity"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
@ -21,7 +21,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.mobilefl"
applicationId = "com.example.identity"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion

View File

@ -1,6 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="mobilefl"
android:label="identity"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity

View File

@ -1,4 +1,4 @@
package com.example.mobilefl
package com.example.identity
import io.flutter.embedding.android.FlutterActivity

BIN
assets/images/hunter1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
assets/images/hunter2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
assets/images/hunter3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
assets/images/survivor1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
assets/images/survivor2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
assets/images/survivor3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

87
lib/character.dart Normal file
View File

@ -0,0 +1,87 @@
enum CharacterType { Survivor, Hunter }
class Character {
final String name;
final CharacterType type;
final String backstory;
final String imageUrl;
bool isLiked;
Character({
required this.name,
required this.type,
required this.backstory,
required this.imageUrl,
this.isLiked = false, // Значение по умолчанию - false
});
factory Character.fromJson(Map<String, dynamic> json) {
try {
CharacterType characterType;
if (json['type'] == 'Выживший') {
characterType = CharacterType.Survivor;
} else if (json['type'] == 'Охотник') {
characterType = CharacterType.Hunter;
} else {
throw Exception('Неизвестный тип персонажа: ${json['type']}');
}
return Character(
name: json['name'],
type: characterType,
backstory: json['backstory'],
imageUrl: json['image_url'], // Используем корректный URL
);
} catch (e) {
print("Ошибка при парсинге данных: $e");
throw Exception('Ошибка при парсинге персонажа');
}
}
// Преобразуем тип обратно в строку
String get typeString {
switch (type) {
case CharacterType.Survivor:
return 'Выживший';
case CharacterType.Hunter:
return 'Охотник';
default:
return 'Неизвестно';
}
}
String getInfo() {
return '$typeString - $backstory';
}
static empty() {
return null;
}
}
class Survivor extends Character {
Survivor({
required String name,
required String backstory,
required String imageUrl,
}) : super(
name: name,
backstory: backstory,
imageUrl: imageUrl,
type: CharacterType.Survivor,
);
}
class Hunter extends Character {
Hunter({
required String name,
required String backstory,
required String imageUrl,
}) : super(
name: name,
backstory: backstory,
imageUrl: imageUrl,
type: CharacterType.Hunter,
);
}

View File

@ -0,0 +1,23 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'character.dart';
const String baseUrl = 'http://192.168.1.83:5000'; // IP-адрес вместо localhost
class CharacterService {
Future<List<Character>> getCharacters({String search = ''}) async {
try {
final response = await http.get(Uri.parse('$baseUrl/characters?search=$search'));
if (response.statusCode == 200) {
final List<dynamic> data = json.decode(response.body);
return data.map((item) => Character.fromJson(item)).toList();
} else {
throw Exception('Ошибка загрузки данных с сервера. Статус: ${response.statusCode}');
}
} catch (e) {
print('Ошибка при получении данных: $e');
throw Exception('Не удалось загрузить персонажей');
}
}
}

View File

@ -1,70 +1,183 @@
import 'package:flutter/material.dart';
import 'character.dart';
import 'character_service.dart';
import 'pages/CharacterDetailPage.dart';
void main() {
runApp(const MyApp());
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const MyHomePage(title: 'Камчарова Ксения Алексеевна'),
title: 'Identity V Characters',
home: MyHomePage(title: 'Персонажи Identity V'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
final CharacterService _characterService = CharacterService();
late Future<List<Character>> _futureCharacters;
final TextEditingController _searchController = TextEditingController();
void _incrementCounter() {
@override
void initState() {
super.initState();
_futureCharacters = _characterService.getCharacters();
}
void _searchCharacters(String query) {
setState(() {
_counter++;
_futureCharacters = _characterService.getCharacters(search: query);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
title: Text(widget.title),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {
showSearch(
context: context,
delegate: CharacterSearchDelegate(_searchCharacters),
);
},
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
body: FutureBuilder<List<Character>>(
future: _futureCharacters,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Ошибка: ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(child: Text('Нет персонажей'));
} else {
final characters = snapshot.data!;
return ListView.builder(
itemCount: characters.length,
itemBuilder: (context, index) {
final character = characters[index];
return ListTile(
leading: SizedBox(
width: 40,
child: Image.network(character.imageUrl, width: 50, height: 50),
),
title: Text(character.name),
subtitle: Text(character.typeString),
trailing: IconButton(
icon: Icon(
character.isLiked ? Icons.favorite : Icons.favorite_border,
color: character.isLiked ? Colors.red : null,
),
onPressed: () {
setState(() {
character.isLiked = !character.isLiked;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
character.isLiked
? '${character.name} понравился вам!'
: '${character.name} убран из лайков.',
),
duration: Duration(seconds: 2),
),
);
},
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CharacterDetailPage(character: character),
),
);
},
);
},
);
}
},
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), );
);
}
}
class CharacterSearchDelegate extends SearchDelegate {
final Function(String) onSearch;
CharacterSearchDelegate(this.onSearch);
@override
Widget buildSuggestions(BuildContext context) {
return ListView();
}
@override
Widget buildResults(BuildContext context) {
onSearch(query); // Выполняем поиск
return FutureBuilder<List<Character>>(
future: CharacterService().getCharacters(search: query), // Запрашиваем персонажей с фильтром
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Ошибка: ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(child: Text('Нет результатов для "$query"'));
} else {
final characters = snapshot.data!;
return ListView.builder(
itemCount: characters.length,
itemBuilder: (context, index) {
final character = characters[index];
return ListTile(
title: Text(character.name),
subtitle: Text(character.typeString),
);
},
);
}
},
);
}
@override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = ''; // Очищаем запрос
},
),
];
}
@override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
close(context, null); // Закрываем поиск
},
);
}
}

View File

@ -0,0 +1,61 @@
import 'package:flutter/material.dart';
import '../character.dart';
class CharacterDetailPage extends StatelessWidget {
final Character character;
CharacterDetailPage({required this.character});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(character.name),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Изображение персонажа
Center(
child: Image.network(
character.imageUrl,
height: 200,
width: 200,
fit: BoxFit.cover,
),
),
SizedBox(height: 20),
Text(
character.name, // Имя персонажа
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
SizedBox(height: 10),
Text(
character.typeString, // Тип персонажа (Survivor или Hunter)
style: TextStyle(fontSize: 18, color: Colors.grey[600]),
),
SizedBox(height: 20),
// Предыстория персонажа
Text(
'Полное описание:',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
SizedBox(height: 10),
// Текст предыстории
Text(
character.backstory,
style: TextStyle(fontSize: 14),
maxLines: null,
softWrap: true,
),
],
),
),
);
}
}

View File

@ -75,6 +75,22 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
http:
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev"
source: hosted
version: "1.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
leak_tracker:
dependency: transitive
description:
@ -192,6 +208,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.2"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vector_math:
dependency: transitive
description:
@ -208,6 +232,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "14.2.5"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev"
source: hosted
version: "1.1.0"
sdks:
dart: ">=3.5.2 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"

View File

@ -1,4 +1,6 @@
name: mobilefl
name: identity
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
@ -30,7 +32,7 @@ environment:
dependencies:
flutter:
sdk: flutter
http: ^1.2.2
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
@ -52,6 +54,8 @@ dev_dependencies:
# The following section is specific to Flutter packages.
flutter:
assets:
- assets/images/
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in

View File

@ -8,12 +8,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mobilefl/main.dart';
import 'package:identity/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
await tester.pumpWidget(MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);

View File

@ -23,13 +23,13 @@
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="mobilefl">
<meta name="apple-mobile-web-app-title" content="identity">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>mobilefl</title>
<title>identity</title>
<link rel="manifest" href="manifest.json">
</head>
<body>

View File

@ -1,6 +1,6 @@
{
"name": "mobilefl",
"short_name": "mobilefl",
"name": "identity",
"short_name": "identity",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",

View File

@ -1,108 +0,0 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.14)
project(mobilefl LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "mobilefl")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(VERSION 3.14...3.25)
# Define build configuration option.
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(IS_MULTICONFIG)
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
CACHE STRING "" FORCE)
else()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
endif()
# Define settings for the Profile build mode.
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
# Use Unicode for all projects.
add_definitions(-DUNICODE -D_UNICODE)
# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_17)
target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
target_compile_options(${TARGET} PRIVATE /EHsc)
target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
endfunction()
# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})
# Application build; see runner/CMakeLists.txt.
add_subdirectory("runner")
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# Support files are copied into place next to the executable, so that it can
# run in place. This is done instead of making a separate bundle (as on Linux)
# so that building and running from within Visual Studio will work.
set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
# Make the "install" step default, as it's required to run.
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
if(PLUGIN_BUNDLED_LIBRARIES)
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()
# Copy the native assets provided by the build.dart from all packages.
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
CONFIGURATIONS Profile;Release
COMPONENT Runtime)

View File

@ -90,12 +90,12 @@ BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "com.example" "\0"
VALUE "FileDescription", "mobilefl" "\0"
VALUE "FileDescription", "identity" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "mobilefl" "\0"
VALUE "InternalName", "identity" "\0"
VALUE "LegalCopyright", "Copyright (C) 2024 com.example. All rights reserved." "\0"
VALUE "OriginalFilename", "mobilefl.exe" "\0"
VALUE "ProductName", "mobilefl" "\0"
VALUE "OriginalFilename", "identity.exe" "\0"
VALUE "ProductName", "identity" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"
END
END

View File

@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
FlutterWindow window(project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
if (!window.Create(L"mobilefl", origin, size)) {
if (!window.Create(L"identity", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);