laboratory_2

This commit is contained in:
nikbel2004@outlook.com 2024-09-17 00:43:15 +04:00
parent d3d8b23724
commit a3214bce28
11 changed files with 596 additions and 64 deletions

69
lib/ProductCode.txt Normal file
View File

@ -0,0 +1,69 @@
// Classes +
// Methods +
// Enums +
// Loops +
// Generics (List<>) +
// Anonymous functions +
// Future +
// Extension +
enum Type { tools, electrics, materials, gas }
extension ProductEx on Product {
double get discountedPrice => price * 0.9;
String get fullname => '${name} - \$${price}';
}
class Product {
String name;
double price;
int quantity;
Type type;
// Конструктор
Product(this.name, this.price, this.quantity, this.type);
}
class Cart {
final List<Product> items = [];
void push(Product p) {
items.add(p);
}
double getTotalPrice() {
double price = 0;
for (int i = 0; i < items.length; i++) {
price += items[i].quantity * items[i].price;
}
return price;
}
int getItemsCount() {
return items.fold(0, (total, item) => total + item.quantity);
}
Future<List<Product>> getItemsAsync() async {
await Future.delayed(Duration(seconds: 3));
return items;
}
}
void main() {
Cart cart = Cart();
Product product = Product('hammer', 1000.0, 4, Type.tools);
cart.push(product);
cart.push(Product('brick', 500.0, 2, Type.materials));
print('Total price: \$${cart.getTotalPrice()}');
print('Total items count: ${cart.getItemsCount()}');
print('Product fullname: ${product.fullname}');
print('Product with discount: ${product.discountedPrice}');
Future.delayed(Duration(seconds: 5)).then((_) => print(product.name));
List<Product> products = await cart.getItemAsync();
print('Number elements from async method: ${products.length}');
}

View File

@ -0,0 +1,119 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'property_provider.dart';
import 'property_model.dart';
class AddPropertyDialog extends StatefulWidget {
@override
_AddPropertyDialogState createState() => _AddPropertyDialogState();
}
class _AddPropertyDialogState extends State<AddPropertyDialog> {
final _formKey = GlobalKey<FormState>();
String _title = '';
String? _description;
String _location = '';
DateTime _daterent = DateTime.now();
double _price = 0.0;
PropertyType _selectedType = PropertyType.apartment;
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Add New Property'),
content: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
decoration: InputDecoration(labelText: 'Property Title*'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a property title';
}
return null;
},
onSaved: (value) {
_title = value ?? '';
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Description (optional)'),
onSaved: (value) {
_description = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Location*'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a location';
}
return null;
},
onSaved: (value) {
_location = value ?? '';
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Price*'),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a price';
}
if (double.tryParse(value) == null) {
return 'Please enter a valid number';
}
return null;
},
onSaved: (value) {
_price = double.tryParse(value!) ?? 0.0;
},
),
DropdownButton<PropertyType>(
value: _selectedType,
onChanged: (PropertyType? newValue) {
setState(() {
_selectedType = newValue!;
});
},
items: PropertyType.values.map((PropertyType type) {
return DropdownMenuItem<PropertyType>(
value: type,
child: Text(type.toString().split('.').last),
);
}).toList(),
),
],
),
),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
ElevatedButton(
child: Text('Add Property'),
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
Provider.of<PropertyProvider>(context, listen: false).addProperty(
title: _title,
description: _description,
daterent: _daterent,
location: _location,
price: _price,
type: _selectedType,
);
Navigator.of(context).pop();
}
},
),
],
);
}
}

View File

@ -1,80 +1,31 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:pmd/property_list_screen.dart';
import 'package:pmd/property_provider.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const MyApp());
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => PropertyProvider()),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
title: 'Property List',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
primarySwatch: Colors.cyan,
),
home: const MyHomePage(title: 'Белянин Никита ПИбд-31'),
home: PropertyListScreen(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
Color _color = Colors.orangeAccent;
void _incrementCounter() {
setState(() {
_counter++;
_color = Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: _color,
title: Text(widget.title),
),
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,
),
if (_counter > 15)
Text(
'Хватит тыкать! Не Тыкай',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
backgroundColor: _color,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
}

7
lib/price_extension.dart Normal file
View File

@ -0,0 +1,7 @@
import 'package:pmd/property_model.dart';
extension PropertyExtension on Property {
String formattedPrice() {
return '\$${price.toStringAsFixed(2)}';
}
}

View File

@ -0,0 +1,18 @@
import 'package:pmd/property_model.dart';
extension PropertyDescriptionExtension on Property {
// Проверка наличия описания
bool get hasDescription => description != null && description!.isNotEmpty;
// Установка описания по умолчанию, если оно пустое
void setDefaultDescriptionIfEmpty(String defaultDescription) {
if (!hasDescription) {
description = defaultDescription;
}
}
// Получение описания с дефолтным значением
String getDescriptionOrDefault(String defaultDescription) {
return hasDescription ? description! : defaultDescription;
}
}

View File

@ -0,0 +1,116 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'property_model.dart';
import 'property_provider.dart';
import 'property_description_extension.dart';
class PropertyDetailsScreen extends StatefulWidget {
final Property property;
PropertyDetailsScreen({required this.property});
@override
_PropertyDetailsScreenState createState() => _PropertyDetailsScreenState();
}
class _PropertyDetailsScreenState extends State<PropertyDetailsScreen> {
late TextEditingController _priceController;
@override
void initState() {
super.initState();
_priceController =
TextEditingController(text: widget.property.price.toString());
}
@override
void dispose() {
_priceController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.property.title),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Location: ${widget.property.location}',
style: TextStyle(fontSize: 16)),
SizedBox(height: 8),
Text('Price: \$${widget.property.price.toStringAsFixed(2)}',
style: TextStyle(fontSize: 16)),
SizedBox(height: 8),
Text('Type: ${widget.property.type.name}',
style: TextStyle(fontSize: 16)),
SizedBox(height: 16),
Text('Description:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Text(
widget.property.getDescriptionOrDefault('No description available'),
style: TextStyle(fontSize: 16)),
SizedBox(height: 16),
Text('Available: ${widget.property.isAvailable ? "Yes" : "No"}',
style: TextStyle(fontSize: 16)),
SizedBox(height: 16),
// Поле для изменения цены
TextField(
controller: _priceController,
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: 'New Price'),
),
SizedBox(height: 16),
// Кнопка для изменения доступности
ElevatedButton(
onPressed: () {
context
.read<PropertyProvider>()
.togglePropertyAvailability(widget.property);
setState(
() {}); // Обновляем интерфейс после изменения доступности
},
child: Text(widget.property.isAvailable
? 'Set as Not Available'
: 'Set as Available'),
),
SizedBox(height: 16),
// Кнопка для изменения цены
ElevatedButton(
onPressed: () {
double? newPrice = double.tryParse(_priceController.text);
if (newPrice != null) {
context
.read<PropertyProvider>()
.updatePropertyPrice(widget.property, newPrice);
setState(() {}); // Обновляем интерфейс после изменения цены
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Please enter a valid price')),
);
}
},
child: Text('Update Price'),
),
ElevatedButton(
onPressed: () {
// Пример использования расширения для установки описания по умолчанию
widget.property.setDefaultDescriptionIfEmpty('Default description for this property.');
// Обновите интерфейс, если необходимо
},
child: Text('Update Description'),
)
],
),
),
);
}
}

View File

@ -0,0 +1,108 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'property_provider.dart';
import 'property_details_screen.dart';
import 'add_property_dialog.dart';
import 'property_model.dart';
class PropertyListScreen extends StatefulWidget {
@override
_PropertyListScreenState createState() => _PropertyListScreenState();
}
class _PropertyListScreenState extends State<PropertyListScreen> {
Color _color = Colors.transparent;
@override
void initState() {
super.initState();
Provider.of<PropertyProvider>(context, listen: false).loadProperties();
_color =
Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: _color,
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Property List',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
Text(
'made by RentHub',
style: TextStyle(
fontSize: 12,
fontStyle: FontStyle.italic,
),
),
],
),
actions: [
IconButton(
icon: Icon(Icons.sort),
onPressed: () {
context.read<PropertyProvider>().sortPropertiesByPrice();
},
),
],
),
body: Consumer<PropertyProvider>(
builder: (context, propertyProvider, child) {
if (propertyProvider.properties.isEmpty) {
return Center(child: Text('No properties available.'));
}
return ListView.builder(
itemCount: propertyProvider.properties.length,
itemBuilder: (context, index) {
Property property = propertyProvider.properties[index];
return ListTile(
title: Text(property.title),
subtitle: Text(
'${property.location} - \$${property.price.toStringAsFixed(2)}'),
trailing: Checkbox(
value: property.isAvailable,
onChanged: (value) {
context
.read<PropertyProvider>()
.togglePropertyAvailability(property);
},
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
PropertyDetailsScreen(property: property),
),
);
},
onLongPress: () {
context.read<PropertyProvider>().removeProperty(property);
},
);
},
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _openAddPropertyDialog(context),
backgroundColor: _color,
child: Icon(Icons.add),
),
);
}
void _openAddPropertyDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return AddPropertyDialog();
},
);
}
}

26
lib/property_model.dart Normal file
View File

@ -0,0 +1,26 @@
enum PropertyType {
apartment,
flat,
house,
atelier
}
class Property {
final String title;
String? description;
final String? location;
final DateTime? daterent;
double price;
bool isAvailable;
PropertyType type;
Property ({
required this.title,
this.description,
required this.location,
this.daterent,
required this.price,
this.isAvailable = false,
this.type = PropertyType.flat,
});
}

View File

@ -0,0 +1,92 @@
import 'package:flutter/material.dart';
import 'property_model.dart';
class PropertyProvider with ChangeNotifier {
List<Property> _properties = <Property>[];
List<Property> get properties => _properties;
// Добавление недвижимости
void addProperty({
required String title,
String? description,
required String location,
required DateTime? daterent,
required double price,
PropertyType type = PropertyType.house,
}) {
final house = Property(
title: title,
description: description,
location: location,
daterent: daterent,
price: price,
type: type,
);
_properties.add(house);
notifyListeners();
}
// Обновление цены недвижимости
void updatePropertyPrice(Property property, double newPrice) {
property.price = newPrice;
notifyListeners();
}
// Удаление записи (о недвижимости)
void removeProperty(Property property) {
_properties.remove(property);
notifyListeners();
}
// Вывод
void printAvailableProperties(List<Property> properties) {
for (var property in properties) {
if (property.isAvailable) {
print('${property.title} is available for \$${property.price.toStringAsFixed(2)}');
}
}
}
// Сортировка недвижимости по цене
void sortPropertiesByPrice() {
_properties.sort((a, b) => a.price.compareTo(b.price));
notifyListeners();
}
// Изменение доступности недвижимости (переименовано в togglePropertyAvailability)
void togglePropertyAvailability(Property property) {
property.isAvailable = !property.isAvailable;
notifyListeners();
}
// Асинхронная загрузка записей (loadProperties)
Future<void> loadProperties() async {
// Имитируем задержку сети, запрос к бэку
await Future.delayed(Duration(seconds: 2));
if (_properties.isEmpty) {
_properties = [
Property(
title: "Apartment1",
type: PropertyType.apartment,
location: "Moscow",
daterent: DateTime.now().add(Duration(days: 1)),
price: 1200.0),
Property(
title: "Apartment2",
type: PropertyType.apartment,
location: "Moscow",
daterent: DateTime.now().add(Duration(days: 5)),
price: 1500.0),
Property(
title: "Flat2",
type: PropertyType.flat,
location: "Samara",
daterent: DateTime.now().add(Duration(days: 1)),
price: 1100.0),
];
}
notifyListeners();
}
}

View File

@ -75,6 +75,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
intl:
dependency: "direct main"
description:
name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev"
source: hosted
version: "0.18.1"
leak_tracker:
dependency: transitive
description:
@ -131,6 +139,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.15.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
path:
dependency: transitive
description:
@ -139,6 +155,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.0"
provider:
dependency: "direct main"
description:
name: provider
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev"
source: hosted
version: "6.1.2"
sky_engine:
dependency: transitive
description: flutter

View File

@ -31,6 +31,8 @@ dependencies:
flutter:
sdk: flutter
provider: ^6.0.0
intl: ^0.18.0
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.