laboratory_3

This commit is contained in:
nikbel2004@outlook.com 2024-09-17 03:13:55 +04:00
parent a3214bce28
commit a0f7bb995e
9 changed files with 107 additions and 572 deletions

View File

@ -1,69 +0,0 @@
// 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

@ -1,119 +0,0 @@
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,31 +1,121 @@
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(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => PropertyProvider()),
],
child: MyApp(),
),
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Property List',
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.cyan,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
useMaterial3: true,
),
home: PropertyListScreen(),
home: const MyHomePage(title: 'Laboratory 3: Cards'),
);
}
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme
.of(context)
.colorScheme
.inversePrimary,
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(30),
child: ListView.separated(
itemBuilder: (context, index) =>
Card(name: "House $index", location: "Moscow", price: 1100.0),
separatorBuilder: (context, index) => const SizedBox(height: 20),
itemCount: 5,
)));
}
}
class Card extends StatefulWidget {
const Card({super.key, required this.name, required this.price, required this.location});
final String name;
final double price;
final String location;
@override
State<StatefulWidget> createState() => _CardState();
}
class _CardState extends State<Card> {
bool _isFavorite = false;
void toggleIsFavorite() {
setState(() {
_isFavorite = !_isFavorite;
});
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
padding:
const EdgeInsets.only(top: 50, bottom: 15, left: 40, right: 40),
decoration: BoxDecoration(
border: Border.all(color: Colors.black12, width: 2),
borderRadius: BorderRadius.circular(20)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Image.network(
"https://cdn0.youla.io/files/images/780_780/63/29/6329d9f543eedb62b7695786-1.jpg"),
),
Padding(
padding: EdgeInsets.only(top: 50),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(widget.name, style: TextStyle(fontSize: 17)),
Text("Местоположение: ${widget.location}", style: TextStyle(fontSize: 15)),
Text("${widget.price} Рублей/сутки",
style: TextStyle(
fontSize: 17, color: Colors.orange))
],
),
)
],
),
),
Positioned(
right: 300,
top: 10,
child: IconButton(
icon: Icon(_isFavorite ? Icons.favorite : Icons.favorite_border),
color: Colors.red,
onPressed: toggleIsFavorite,
))
],
);
}
}

View File

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

View File

@ -1,18 +0,0 @@
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

@ -1,116 +0,0 @@
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

@ -1,108 +0,0 @@
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();
},
);
}
}

View File

@ -1,26 +0,0 @@
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

@ -1,92 +0,0 @@
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();
}
}