Приложение для Osclass на Flutter с использованием REST API
Цитата: administrator от 30.05.2025, 14:14Ниже представлен базовый каркас мобильного приложения для работы с Osclass через REST API на Flutter/Dart. Это приложение будет отображать объявления и категории из вашей Osclass системы.
Основные файлы приложения
1.
main.dart
- Главный файл приложенияimport 'package:flutter/material.dart'; import 'package:osclass_app/screens/home_screen.dart'; import 'package:osclass_app/services/api_service.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Osclass App', theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: const HomeScreen(), debugShowCheckedModeBanner: false, ); } }2.
api_service.dart
- Сервис для работы с API Osclassimport 'dart:convert'; import 'package:http/http.dart' as http; class ApiService { static const String _baseUrl = 'https://your-osclass-site.com/api'; static const String _apiKey = 'YOUR_API_KEY'; Future<List<dynamic>> getLatestItems() async { final response = await http.get( Uri.parse('$_baseUrl/items/search?limit=20'), headers: {'Authorization': 'Bearer $_apiKey'}, ); if (response.statusCode == 200) { return json.decode(response.body)['items']; } else { throw Exception('Failed to load items'); } } Future<List<dynamic>> getCategories() async { final response = await http.get( Uri.parse('$_baseUrl/categories'), headers: {'Authorization': 'Bearer $_apiKey'}, ); if (response.statusCode == 200) { return json.decode(response.body)['categories']; } else { throw Exception('Failed to load categories'); } } Future<dynamic> getItemDetails(int itemId) async { final response = await http.get( Uri.parse('$_baseUrl/items/$itemId'), headers: {'Authorization': 'Bearer $_apiKey'}, ); if (response.statusCode == 200) { return json.decode(response.body); } else { throw Exception('Failed to load item details'); } } }3.
models/item_model.dart
- Модель данных объявленияclass Item { final int id; final String title; final String description; final double price; final String? imageUrl; final String category; final String location; final DateTime date; Item({ required this.id, required this.title, required this.description, required this.price, this.imageUrl, required this.category, required this.location, required this.date, }); factory Item.fromJson(Map<String, dynamic> json) { return Item( id: json['id'], title: json['title'], description: json['description'], price: double.tryParse(json['price']?.toString() ?? '0') ?? 0, imageUrl: json['images']?.isNotEmpty == true ? json['images'][0] : null, category: json['category_name'] ?? 'Unknown', location: json['city_name'] ?? 'Unknown location', date: DateTime.parse(json['dt_pub_date']), ); } }4.
screens/home_screen.dart
- Главный экран приложенияimport 'package:flutter/material.dart'; import 'package:osclass_app/models/item_model.dart'; import 'package:osclass_app/services/api_service.dart'; import 'package:osclass_app/widgets/item_card.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { final ApiService _apiService = ApiService(); List<Item> _items = []; bool _isLoading = true; @override void initState() { super.initState(); _loadItems(); } Future<void> _loadItems() async { try { final items = await _apiService.getLatestItems(); setState(() { _items = items.map((json) => Item.fromJson(json)).toList(); _isLoading = false; }); } catch (e) { setState(() { _isLoading = false; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error loading items: ${e.toString()}')), ); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Osclass App'), actions: [ IconButton( icon: const Icon(Icons.search), onPressed: () { // Реализация поиска }, ), ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : ListView.builder( itemCount: _items.length, itemBuilder: (context, index) { return ItemCard(item: _items[index]); }, ), floatingActionButton: FloatingActionButton( onPressed: () { // Переход к экрану добавления объявления }, child: const Icon(Icons.add), ), ); } }5.
widgets/item_card.dart
- Виджет карточки объявленияimport 'package:flutter/material.dart'; import 'package:osclass_app/models/item_model.dart'; class ItemCard extends StatelessWidget { final Item item; const ItemCard({super.key, required this.item}); @override Widget build(BuildContext context) { return Card( margin: const EdgeInsets.all(8.0), child: InkWell( onTap: () { // Переход к деталям объявления }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (item.imageUrl != null) Image.network( item.imageUrl!, height: 150, width: double.infinity, fit: BoxFit.cover, ), Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 4), Text( '$${item.price.toStringAsFixed(2)}', style: const TextStyle( fontSize: 16, color: Colors.green, ), ), const SizedBox(height: 4), Row( children: [ const Icon(Icons.location_on, size: 16), const SizedBox(width: 4), Text(item.location), ], ), Row( children: [ const Icon(Icons.category, size: 16), const SizedBox(width: 4), Text(item.category), ], ), ], ), ), ], ), ), ); } }Настройка проекта
Добавьте необходимые зависимости в
pubspec.yaml
:dependencies: flutter: sdk: flutter http: ^0.13.5 intl: ^0.18.1 cached_network_image: ^3.2.3
Для работы с API Osclass вам нужно:
Установить и настроить REST API плагин для Osclass
Получить API ключ
Обновить
_baseUrl
и_apiKey
вapi_service.dart
Дополнительные возможности для реализации
Экран деталей объявления
Поиск по объявлениям
Фильтрация по категориям
Система авторизации
Создание новых объявлений
Избранные объявления
Кэширование данных
Это базовый каркас приложения, который можно расширять в зависимости от ваших требований. Для работы с изображениями рекомендуется использовать пакет
cached_network_image
, а для навигации между экранами -go_router
или стандартныйNavigator
.
Ниже представлен базовый каркас мобильного приложения для работы с Osclass через REST API на Flutter/Dart. Это приложение будет отображать объявления и категории из вашей Osclass системы.
Основные файлы приложения
1. main.dart
- Главный файл приложения
import 'package:flutter/material.dart'; import 'package:osclass_app/screens/home_screen.dart'; import 'package:osclass_app/services/api_service.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Osclass App', theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: const HomeScreen(), debugShowCheckedModeBanner: false, ); } }
2. api_service.dart
- Сервис для работы с API Osclass
import 'dart:convert'; import 'package:http/http.dart' as http; class ApiService { static const String _baseUrl = 'https://your-osclass-site.com/api'; static const String _apiKey = 'YOUR_API_KEY'; Future<List<dynamic>> getLatestItems() async { final response = await http.get( Uri.parse('$_baseUrl/items/search?limit=20'), headers: {'Authorization': 'Bearer $_apiKey'}, ); if (response.statusCode == 200) { return json.decode(response.body)['items']; } else { throw Exception('Failed to load items'); } } Future<List<dynamic>> getCategories() async { final response = await http.get( Uri.parse('$_baseUrl/categories'), headers: {'Authorization': 'Bearer $_apiKey'}, ); if (response.statusCode == 200) { return json.decode(response.body)['categories']; } else { throw Exception('Failed to load categories'); } } Future<dynamic> getItemDetails(int itemId) async { final response = await http.get( Uri.parse('$_baseUrl/items/$itemId'), headers: {'Authorization': 'Bearer $_apiKey'}, ); if (response.statusCode == 200) { return json.decode(response.body); } else { throw Exception('Failed to load item details'); } } }
3. models/item_model.dart
- Модель данных объявления
class Item { final int id; final String title; final String description; final double price; final String? imageUrl; final String category; final String location; final DateTime date; Item({ required this.id, required this.title, required this.description, required this.price, this.imageUrl, required this.category, required this.location, required this.date, }); factory Item.fromJson(Map<String, dynamic> json) { return Item( id: json['id'], title: json['title'], description: json['description'], price: double.tryParse(json['price']?.toString() ?? '0') ?? 0, imageUrl: json['images']?.isNotEmpty == true ? json['images'][0] : null, category: json['category_name'] ?? 'Unknown', location: json['city_name'] ?? 'Unknown location', date: DateTime.parse(json['dt_pub_date']), ); } }
4. screens/home_screen.dart
- Главный экран приложения
import 'package:flutter/material.dart'; import 'package:osclass_app/models/item_model.dart'; import 'package:osclass_app/services/api_service.dart'; import 'package:osclass_app/widgets/item_card.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { final ApiService _apiService = ApiService(); List<Item> _items = []; bool _isLoading = true; @override void initState() { super.initState(); _loadItems(); } Future<void> _loadItems() async { try { final items = await _apiService.getLatestItems(); setState(() { _items = items.map((json) => Item.fromJson(json)).toList(); _isLoading = false; }); } catch (e) { setState(() { _isLoading = false; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error loading items: ${e.toString()}')), ); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Osclass App'), actions: [ IconButton( icon: const Icon(Icons.search), onPressed: () { // Реализация поиска }, ), ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : ListView.builder( itemCount: _items.length, itemBuilder: (context, index) { return ItemCard(item: _items[index]); }, ), floatingActionButton: FloatingActionButton( onPressed: () { // Переход к экрану добавления объявления }, child: const Icon(Icons.add), ), ); } }
5. widgets/item_card.dart
- Виджет карточки объявления
import 'package:flutter/material.dart'; import 'package:osclass_app/models/item_model.dart'; class ItemCard extends StatelessWidget { final Item item; const ItemCard({super.key, required this.item}); @override Widget build(BuildContext context) { return Card( margin: const EdgeInsets.all(8.0), child: InkWell( onTap: () { // Переход к деталям объявления }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (item.imageUrl != null) Image.network( item.imageUrl!, height: 150, width: double.infinity, fit: BoxFit.cover, ), Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 4), Text( '$${item.price.toStringAsFixed(2)}', style: const TextStyle( fontSize: 16, color: Colors.green, ), ), const SizedBox(height: 4), Row( children: [ const Icon(Icons.location_on, size: 16), const SizedBox(width: 4), Text(item.location), ], ), Row( children: [ const Icon(Icons.category, size: 16), const SizedBox(width: 4), Text(item.category), ], ), ], ), ), ], ), ), ); } }
Настройка проекта
-
Добавьте необходимые зависимости в
pubspec.yaml
:
dependencies: flutter: sdk: flutter http: ^0.13.5 intl: ^0.18.1 cached_network_image: ^3.2.3
-
Для работы с API Osclass вам нужно:
-
Установить и настроить REST API плагин для Osclass
-
Получить API ключ
-
Обновить
_baseUrl
и_apiKey
вapi_service.dart
-
Дополнительные возможности для реализации
-
Экран деталей объявления
-
Поиск по объявлениям
-
Фильтрация по категориям
-
Система авторизации
-
Создание новых объявлений
-
Избранные объявления
-
Кэширование данных
Это базовый каркас приложения, который можно расширять в зависимости от ваших требований. Для работы с изображениями рекомендуется использовать пакет cached_network_image
, а для навигации между экранами - go_router
или стандартный Navigator
.