feature(collections): Заготовка под апи. Переключалка коллекций

This commit is contained in:
2025-09-08 16:39:33 +03:00
parent 285c4ca3f2
commit 8b546214eb
11 changed files with 142 additions and 1188 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -8,10 +8,6 @@ clean:
codegen: clean codegen: clean
fvm flutter pub run build_runner build --delete-conflicting-outputs fvm flutter pub run build_runner build --delete-conflicting-outputs
watchgen: clean
fvm flutter pub run build_runner watch --delete-conflicting-outputs
iosPod: iosPod:
cd ios && rm -rf Podfile.lock Pods Runner.xcworkspace && fvm flutter clean && fvm flutter pub get && pod install cd ios && rm -rf Podfile.lock Pods Runner.xcworkspace && fvm flutter clean && fvm flutter pub get && pod install
@@ -31,8 +27,8 @@ macosPodUpdate:
cd macos && pod install --repo-update cd macos && pod install --repo-update
androidBuild: clean androidBuild: clean
fvm flutter build apk --split-per-abi fvm flutter build apk
mv `pwd`/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk /tmp/$(PROJECT_NAME)-$(env)-$(ver).apk mv `pwd`/build/app/outputs/flutter-apk/app-release.apk /tmp/$(PROJECT_NAME)-$(env)-$(ver).apk
echo /tmp/$(PROJECT_NAME)-$(env)-$(ver).apk echo /tmp/$(PROJECT_NAME)-$(env)-$(ver).apk
open /tmp open /tmp

View File

@@ -2,6 +2,8 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:dio_smart_retry/dio_smart_retry.dart'; import 'package:dio_smart_retry/dio_smart_retry.dart';
import 'package:remever/common/functions.dart'; import 'package:remever/common/functions.dart';
import 'package:remever/common/resources.dart';
import 'package:remever/common/storage.dart';
import 'package:talker_dio_logger/talker_dio_logger_interceptor.dart'; import 'package:talker_dio_logger/talker_dio_logger_interceptor.dart';
import 'package:talker_dio_logger/talker_dio_logger_settings.dart'; import 'package:talker_dio_logger/talker_dio_logger_settings.dart';
@@ -17,17 +19,17 @@ InterceptorsWrapper get _auth {
RequestOptions options, RequestOptions options,
RequestInterceptorHandler handler, RequestInterceptorHandler handler,
) async { ) async {
// try { try {
// String? token = await authSecStorage.read(key: StorageKeys.authToken); String? token = await authSecStorage.read(key: StorageKeys.accessToken);
// if (token != null) { if (token != null) {
// options.headers['Authorization'] = 'Bearer $token'; options.headers['Authorization'] = 'Bearer $token';
// } }
// } catch (e) { } catch (e) {
// getIt<LogService>().log( // getIt<LogService>().log(
// entity: LogEntity.error(message: 'Error to load access token $e'), // entity: LogEntity.error(message: 'Error to load access token $e'),
// ); // );
// } }
return handler.next(options); return handler.next(options);
}, },

View File

@@ -12,6 +12,8 @@ import 'package:remever/screens/collections/widgets/collection_card.dart';
import 'package:remever/screens/collections/widgets/collections_app_bar.dart'; import 'package:remever/screens/collections/widgets/collections_app_bar.dart';
import 'package:remever/screens/collections/widgets/collections_filters.dart'; import 'package:remever/screens/collections/widgets/collections_filters.dart';
import 'package:remever/services/collection/collections_interface.dart'; import 'package:remever/services/collection/collections_interface.dart';
import 'package:remever/services/collection/collections_service.dart';
import 'package:remever/services/tickets/tickets_interface.dart';
@RoutePage() @RoutePage()
class CollectionScreen extends StatefulWidget { class CollectionScreen extends StatefulWidget {

View File

@@ -1,12 +1,8 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:remever/common/resources.dart'; import 'package:remever/common/resources.dart';
import 'package:remever/common/widgets/typography.dart'; import 'package:remever/common/widgets/typography.dart';
import 'package:remever/common/widgets/wspace.dart';
import 'package:remever/components/extensions/context.dart'; import 'package:remever/components/extensions/context.dart';
import 'package:remever/components/extensions/state.dart'; import 'package:remever/components/extensions/state.dart';
import 'package:remever/widgets/debug/app_debug.dart';
class CollectionsFilters extends StatefulWidget { class CollectionsFilters extends StatefulWidget {
const CollectionsFilters({super.key}); const CollectionsFilters({super.key});
@@ -16,37 +12,52 @@ class CollectionsFilters extends StatefulWidget {
} }
class _CollectionsFiltersState extends State<CollectionsFilters> { class _CollectionsFiltersState extends State<CollectionsFilters> {
static const List<String> _filterOptions = ['Все', 'Публичные', 'Подписки'];
String _selected = 'Все';
void _onFilterSelected(String title) {
safeSetState(() {
_selected = title;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AppDebug( return Padding(
builder: (context, isDebug) { padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 28).r,
if (!isDebug) return HSpace(20); child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
return Padding( children: _buildFilterButtons(),
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 28).r, ),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
_buildFilterButton(AppColors.white, 'Все', () {
safeSetState(() {});
}),
_buildFilterButton(AppColors.gray_bg, 'Публичные', () {
safeSetState(() {});
}),
_buildFilterButton(AppColors.gray_bg, 'Подписки', () {
safeSetState(() {});
}),
],
),
);
},
); );
} }
/// List<Widget> _buildFilterButtons() {
/// Построение кнопки фильтра return _filterOptions
/// .map(
Widget _buildFilterButton(Color color, String title, void Function()? onTap) { (title) => _FilterButton(
title: title,
isSelected: _selected == title,
onTap: () => _onFilterSelected(title),
),
)
.toList();
}
}
class _FilterButton extends StatelessWidget {
final String title;
final bool isSelected;
final VoidCallback onTap;
const _FilterButton({
required this.title,
required this.isSelected,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: onTap, onTap: onTap,
child: Container( child: Container(
@@ -54,7 +65,7 @@ class _CollectionsFiltersState extends State<CollectionsFilters> {
height: 36.h, height: 36.h,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(16)).r, borderRadius: const BorderRadius.all(Radius.circular(16)).r,
color: color, color: isSelected ? AppColors.white : AppColors.bg,
), ),
child: Center(child: AppTypography(title, type: SemiBold14px())), child: Center(child: AppTypography(title, type: SemiBold14px())),
), ),

View File

@@ -5,6 +5,10 @@ import 'package:remever/models/crud_collection_dto.dart';
/// Интерфейс взаимодействия с коллекциями /// Интерфейс взаимодействия с коллекциями
/// ///
abstract interface class CollectionsInterface { abstract interface class CollectionsInterface {
/// работа с api
Future<void> getCollectionsFromApi();
Future<void> createCollectionApi();
/// Получение списка коллекций /// Получение списка коллекций
Stream<List<Collection>> watchCollectionsList({String? search}); Stream<List<Collection>> watchCollectionsList({String? search});

View File

@@ -1,4 +1,6 @@
import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart'; import 'package:injectable/injectable.dart';
import 'package:remever/common/services/api_client.dart';
import 'package:remever/database/database.dart'; import 'package:remever/database/database.dart';
import 'package:remever/inject.dart'; import 'package:remever/inject.dart';
import 'package:remever/models/crud_collection_dto.dart'; import 'package:remever/models/crud_collection_dto.dart';
@@ -35,4 +37,37 @@ final class CollectionsService implements CollectionsInterface {
// TODO: implement makeCollectionPublic // TODO: implement makeCollectionPublic
throw UnimplementedError(); throw UnimplementedError();
} }
@override
Future<void> getCollectionsFromApi() async {
try {
final Response<dynamic> response = await apiClient.get(
'/collections',
queryParameters: <String, dynamic>{'perPage': 20, 'page': 1},
);
print('data');
} catch (e) {
print('Response error $e');
}
}
@override
Future<void> createCollectionApi() async {
try {
final Response<dynamic> response = await apiClient.post(
'/collections',
data: {
"title": "Основы программирования для утюгов",
"description":
"Коллекция карточек по основам программирования для начинающих",
"is_public": true,
},
);
print('data');
} catch (e) {
print('Response error $e');
}
}
} }

View File

@@ -5,6 +5,10 @@ import 'package:remever/models/create_ticket_dto.dart';
/// Интерфейс взаимодействия с билетами в коллекция /// Интерфейс взаимодействия с билетами в коллекция
/// ///
abstract interface class TicketsInterface { abstract interface class TicketsInterface {
/// работа с api
Future<void> getTicketsFromApi();
Future<void> createTicketApi();
/// Получение списка билетов /// Получение списка билетов
Stream<List<Ticket>> watchTicketsList(String collectionId); Stream<List<Ticket>> watchTicketsList(String collectionId);

View File

@@ -1,4 +1,6 @@
import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart'; import 'package:injectable/injectable.dart';
import 'package:remever/common/services/api_client.dart';
import 'package:remever/database/database.dart'; import 'package:remever/database/database.dart';
import 'package:remever/inject.dart'; import 'package:remever/inject.dart';
import 'package:remever/models/create_ticket_dto.dart'; import 'package:remever/models/create_ticket_dto.dart';
@@ -32,4 +34,40 @@ final class TicketsService implements TicketsInterface {
newCollectionId, newCollectionId,
); );
} }
@override
Future<void> getTicketsFromApi() async {
try {
final Response<dynamic> response = await apiClient.get('/cards');
print('data');
} catch (e) {
print('Response error $e');
}
}
@override
Future<void> createTicketApi() async {
try {
final Response<dynamic> response = await apiClient.post(
'/cards',
data: {
"title": "Основы программирования",
"question":
"Коллекция карточек по основам программирования для начинающих",
"question_picture_id": 1,
"answer":
"Коллекция карточек по основам программирования для начинающих",
"answer_picture_id": 2,
"is_public": true,
"is_reverse": false,
"collection_id": 1,
},
);
print('data');
} catch (e) {
print('Response error $e');
}
}
} }

View File

@@ -2,7 +2,7 @@ name: remever
description: "" description: ""
publish_to: 'none' publish_to: 'none'
version: 1.0.0+7 version: 1.0.0+8
environment: environment:
sdk: ^3.7.0 sdk: ^3.7.0