Added pagination to recommand in home
This commit is contained in:
@@ -6,7 +6,7 @@ import 'package:tm_app/data/services/model/recommended_tenders_response/recommen
|
|||||||
|
|
||||||
class HomeRepository {
|
class HomeRepository {
|
||||||
HomeRepository({required HomeService homeService})
|
HomeRepository({required HomeService homeService})
|
||||||
: _homeService = homeService;
|
: _homeService = homeService;
|
||||||
final HomeService _homeService;
|
final HomeService _homeService;
|
||||||
|
|
||||||
Future<Result<HomeResponseModel>> getHome({
|
Future<Result<HomeResponseModel>> getHome({
|
||||||
@@ -15,7 +15,10 @@ class HomeRepository {
|
|||||||
return _homeService.getHome(homeRequestModel: homeRequestModel);
|
return _homeService.getHome(homeRequestModel: homeRequestModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Result<RecommendedTendersResponse>> getHomeRecommendedTenders() async {
|
Future<Result<RecommendedTendersResponse>> getHomeRecommendedTenders({
|
||||||
return _homeService.getRecommendedTenders();
|
required int limit,
|
||||||
|
required int offset,
|
||||||
|
}) async {
|
||||||
|
return _homeService.getRecommendedTenders(limit: limit, offset: offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import '../../core/network/network_manager.dart';
|
|||||||
|
|
||||||
class HomeService {
|
class HomeService {
|
||||||
HomeService({required NetworkManager networkManager})
|
HomeService({required NetworkManager networkManager})
|
||||||
: _networkManager = networkManager;
|
: _networkManager = networkManager;
|
||||||
final NetworkManager _networkManager;
|
final NetworkManager _networkManager;
|
||||||
|
|
||||||
Future<Result<HomeResponseModel>> getHome({
|
Future<Result<HomeResponseModel>> getHome({
|
||||||
@@ -39,9 +39,12 @@ class HomeService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Result<RecommendedTendersResponse>> getRecommendedTenders() async {
|
Future<Result<RecommendedTendersResponse>> getRecommendedTenders({
|
||||||
|
required int limit,
|
||||||
|
required int offset,
|
||||||
|
}) async {
|
||||||
final result = await _networkManager.makeRequest(
|
final result = await _networkManager.makeRequest(
|
||||||
'/api/v1/tenders/recommend',
|
'/api/v1/tenders/recommend?limit=$limit&offset=$offset',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
(json) => RecommendedTendersResponse.fromJson(json),
|
(json) => RecommendedTendersResponse.fromJson(json),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:tm_app/core/utils/result.dart';
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
import 'package:tm_app/data/services/model/home/home_request/home_request_model.dart';
|
import 'package:tm_app/data/services/model/home/home_request/home_request_model.dart';
|
||||||
import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart';
|
import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart';
|
||||||
|
import 'package:tm_app/data/services/model/tender_data/tender_data.dart';
|
||||||
|
|
||||||
import '../data/repositories/home_repository.dart';
|
import '../data/repositories/home_repository.dart';
|
||||||
import '../data/services/model/home/home_response/home_response_model.dart';
|
import '../data/services/model/home/home_response/home_response_model.dart';
|
||||||
@@ -10,9 +11,9 @@ class HomeViewModel with ChangeNotifier {
|
|||||||
final HomeRepository _homeRepository;
|
final HomeRepository _homeRepository;
|
||||||
|
|
||||||
HomeViewModel({required HomeRepository homeRepository})
|
HomeViewModel({required HomeRepository homeRepository})
|
||||||
: _homeRepository = homeRepository {
|
: _homeRepository = homeRepository {
|
||||||
getHome(homeRequestModel: HomeRequestModel(id: '1'));
|
getHome(homeRequestModel: HomeRequestModel(id: '1'));
|
||||||
getHomeRecommandTenders();
|
getHomeRecommandTenders(reset: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
@@ -24,8 +25,14 @@ class HomeViewModel with ChangeNotifier {
|
|||||||
HomeResponseModel? get homeResponse => _homeResponse;
|
HomeResponseModel? get homeResponse => _homeResponse;
|
||||||
|
|
||||||
RecommendedTendersResponse? _recommendedTendersResponse;
|
RecommendedTendersResponse? _recommendedTendersResponse;
|
||||||
RecommendedTendersResponse? get recommendedTendersResponse =>
|
final List<TenderData> _tenders = [];
|
||||||
_recommendedTendersResponse;
|
final int _pageSize = 20;
|
||||||
|
int _currentPage = 0;
|
||||||
|
bool _isLoadingMore = false;
|
||||||
|
bool _hasMore = true;
|
||||||
|
List<TenderData> get tenders => _tenders;
|
||||||
|
bool get isLoadingMore => _isLoadingMore;
|
||||||
|
bool get hasMore => _hasMore;
|
||||||
|
|
||||||
Future<void> getHome({HomeRequestModel? homeRequestModel}) async {
|
Future<void> getHome({HomeRequestModel? homeRequestModel}) async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
@@ -49,23 +56,45 @@ class HomeViewModel with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getHomeRecommandTenders() async {
|
Future<void> getHomeRecommandTenders({bool reset = false}) async {
|
||||||
_isLoading = true;
|
if (_isLoadingMore || (!_hasMore && !reset)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset) {
|
||||||
|
_currentPage = 0;
|
||||||
|
_hasMore = true;
|
||||||
|
_tenders.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoadingMore = true;
|
||||||
_errorMessage = null;
|
_errorMessage = null;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
final result = await _homeRepository.getHomeRecommendedTenders();
|
final result = await _homeRepository.getHomeRecommendedTenders(
|
||||||
|
limit: _pageSize,
|
||||||
|
offset: _currentPage * _pageSize,
|
||||||
|
);
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case Ok<RecommendedTendersResponse>():
|
case Ok<RecommendedTendersResponse>():
|
||||||
_recommendedTendersResponse = result.value;
|
_recommendedTendersResponse = result.value;
|
||||||
|
|
||||||
|
if (_recommendedTendersResponse?.data?.tenders.isNotEmpty ?? false) {
|
||||||
|
_tenders.addAll(
|
||||||
|
_recommendedTendersResponse!.data!.tenders.whereType<TenderData>(),
|
||||||
|
);
|
||||||
|
_currentPage++;
|
||||||
|
} else {
|
||||||
|
_hasMore = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Error<RecommendedTendersResponse>():
|
case Error<RecommendedTendersResponse>():
|
||||||
_errorMessage = result.error.toString();
|
_errorMessage = result.error.toString();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLoading = false;
|
_isLoadingMore = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:tm_app/core/routes/app_routes.dart';
|
|||||||
import 'package:tm_app/core/theme/colors.dart';
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart';
|
import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart';
|
||||||
import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart';
|
|
||||||
import 'package:tm_app/view_models/home_view_model.dart';
|
import 'package:tm_app/view_models/home_view_model.dart';
|
||||||
import 'package:tm_app/views/home/widgets/notification_card.dart';
|
import 'package:tm_app/views/home/widgets/notification_card.dart';
|
||||||
|
|
||||||
@@ -42,7 +41,7 @@ class DesktopHomePage extends StatelessWidget {
|
|||||||
SizedBox(height: 32.0.h()),
|
SizedBox(height: 32.0.h()),
|
||||||
_yourTenderText(),
|
_yourTenderText(),
|
||||||
SizedBox(height: 8.0.h()),
|
SizedBox(height: 8.0.h()),
|
||||||
_bottomListView(homeViewModel.recommendedTendersResponse!),
|
_bottomListView(homeViewModel),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -162,20 +161,38 @@ class DesktopHomePage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _bottomListView(
|
Widget _bottomListView(HomeViewModel homeViewModel) {
|
||||||
RecommendedTendersResponse recommendedTendersResponse,
|
final controller = ScrollController();
|
||||||
) {
|
|
||||||
|
controller.addListener(() {
|
||||||
|
if (controller.position.pixels >=
|
||||||
|
controller.position.maxScrollExtent - 200) {
|
||||||
|
if (!homeViewModel.isLoadingMore && homeViewModel.hasMore) {
|
||||||
|
homeViewModel.getHomeRecommandTenders();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 740,
|
width: 740,
|
||||||
height: 387.0,
|
height: 387.0,
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
|
controller: controller,
|
||||||
padding: EdgeInsets.only(bottom: 20),
|
padding: EdgeInsets.only(bottom: 20),
|
||||||
itemCount: recommendedTendersResponse.data!.tenders.length,
|
itemCount:
|
||||||
|
homeViewModel.tenders.length +
|
||||||
|
(homeViewModel.isLoadingMore ? 1 : 0),
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return TendersListItem(
|
if (index < homeViewModel.tenders.length) {
|
||||||
tender: recommendedTendersResponse.data!.tenders[index]!,
|
return TendersListItem(tender: homeViewModel.tenders[index]);
|
||||||
);
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.0),
|
||||||
|
child: CircularProgressIndicator(color: AppColors.secondary50),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import 'package:tm_app/core/routes/app_routes.dart';
|
|||||||
import 'package:tm_app/core/theme/colors.dart';
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart';
|
import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart';
|
||||||
import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart';
|
|
||||||
import 'package:tm_app/view_models/home_view_model.dart';
|
import 'package:tm_app/view_models/home_view_model.dart';
|
||||||
import 'package:tm_app/views/home/widgets/notification_card.dart';
|
import 'package:tm_app/views/home/widgets/notification_card.dart';
|
||||||
import 'package:tm_app/views/shared/tender_app_bar.dart';
|
import 'package:tm_app/views/shared/tender_app_bar.dart';
|
||||||
@@ -46,7 +45,7 @@ class MobileHomePage extends StatelessWidget {
|
|||||||
_secondTenderCardsRow(homeViewModel.homeResponse!),
|
_secondTenderCardsRow(homeViewModel.homeResponse!),
|
||||||
SizedBox(height: 40.0.h()),
|
SizedBox(height: 40.0.h()),
|
||||||
_yourTenderText(),
|
_yourTenderText(),
|
||||||
_bottomListView(homeViewModel.recommendedTendersResponse!),
|
_bottomListView(homeViewModel),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -164,20 +163,39 @@ class MobileHomePage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _bottomListView(
|
Widget _bottomListView(HomeViewModel homeViewModel) {
|
||||||
RecommendedTendersResponse recommendedTendersResponse,
|
final controller = ScrollController();
|
||||||
) {
|
|
||||||
|
controller.addListener(() {
|
||||||
|
if (controller.position.pixels >=
|
||||||
|
controller.position.maxScrollExtent - 200) {
|
||||||
|
if (!homeViewModel.isLoadingMore && homeViewModel.hasMore) {
|
||||||
|
homeViewModel.getHomeRecommandTenders();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
constraints: BoxConstraints(maxHeight: 387.0.h()),
|
constraints: BoxConstraints(maxHeight: 387.0.h()),
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
|
controller: controller,
|
||||||
padding: EdgeInsets.symmetric(horizontal: 24.0.w(), vertical: 15.0.h()),
|
padding: EdgeInsets.symmetric(horizontal: 24.0.w(), vertical: 15.0.h()),
|
||||||
itemCount: recommendedTendersResponse.data!.tenders.length,
|
itemCount:
|
||||||
|
homeViewModel.tenders.length +
|
||||||
|
(homeViewModel.isLoadingMore ? 1 : 0),
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return TendersListItem(
|
if (index < homeViewModel.tenders.length) {
|
||||||
tender: recommendedTendersResponse.data!.tenders[index]!,
|
return TendersListItem(tender: homeViewModel.tenders[index]);
|
||||||
);
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.0),
|
||||||
|
child: CircularProgressIndicator(color: AppColors.secondary50),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:tm_app/core/routes/app_routes.dart';
|
|||||||
import 'package:tm_app/core/theme/colors.dart';
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart';
|
import 'package:tm_app/data/services/model/home/home_response/home_response_model.dart';
|
||||||
import 'package:tm_app/data/services/model/recommended_tenders_response/recommended_tenders_response.dart';
|
|
||||||
import 'package:tm_app/view_models/home_view_model.dart';
|
import 'package:tm_app/view_models/home_view_model.dart';
|
||||||
import 'package:tm_app/views/home/widgets/notification_card.dart';
|
import 'package:tm_app/views/home/widgets/notification_card.dart';
|
||||||
|
|
||||||
@@ -50,7 +49,7 @@ class TabletHomePage extends StatelessWidget {
|
|||||||
SizedBox(height: 32.0.h()),
|
SizedBox(height: 32.0.h()),
|
||||||
_yourTenderText(),
|
_yourTenderText(),
|
||||||
SizedBox(height: 8.0.h()),
|
SizedBox(height: 8.0.h()),
|
||||||
_bottomListView(homeViewModel.recommendedTendersResponse!),
|
_bottomListView(homeViewModel),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -180,15 +179,36 @@ class TabletHomePage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _bottomListView(RecommendedTendersResponse recommendedTendersResponse) {
|
Widget _bottomListView(HomeViewModel homeViewModel) {
|
||||||
|
final controller = ScrollController();
|
||||||
|
|
||||||
|
controller.addListener(() {
|
||||||
|
if (controller.position.pixels >=
|
||||||
|
controller.position.maxScrollExtent - 200) {
|
||||||
|
if (!homeViewModel.isLoadingMore && homeViewModel.hasMore) {
|
||||||
|
homeViewModel.getHomeRecommandTenders();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 387.0.h(),
|
height: 387.0.h(),
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: recommendedTendersResponse.data!.tenders.length,
|
itemCount:
|
||||||
|
homeViewModel.tenders.length +
|
||||||
|
(homeViewModel.isLoadingMore ? 1 : 0),
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return TendersListItem(tender: recommendedTendersResponse.data!.tenders[index]!);
|
if (index < homeViewModel.tenders.length) {
|
||||||
|
return TendersListItem(tender: homeViewModel.tenders[index]);
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16.0),
|
||||||
|
child: CircularProgressIndicator(color: AppColors.secondary50),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user