Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/analysis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ on:
pull_request:
branches:
- master
- dev
push:
branches:
- master
- dev

jobs:
analysis:
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
name: "Build & Release"

on:
pull_request:
branches:
- master
push:
branches:
- master
Expand Down
13 changes: 7 additions & 6 deletions lib/src/core/bloc/pagination_bloc/pagination_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,24 @@ import 'pagination_state.dart';

extension PaginationStateExtension<T extends Object> on PaginationState<T> {
Widget when({
required Widget Function(List<T> data, bool isLoading) data,
required Widget Function() loading,
required Widget Function(List<T> data) data,
required Widget Function(Object error) error,
required Widget Function(List<T> data) loadingWithData,
required Widget Function(List<T> data, dynamic error) errorWithData,
}) {
return AnimatedSwitcher(
duration: Durations.medium3,
child: switch (this) {
final PaginationLoadedDataState<T> state => data(state.data, false),
final PaginationLoadingWithDataState<T> state => data(
final PaginationLoadedDataState<T> state => data(state.data),
final PaginationLoadingWithDataState<T> state => loadingWithData(
state.data,
true,
),
final PaginationErrorState state => error(state.error),
final PaginationLoadingState _ => loading(),
final PaginationErrorWithLoadedDataState<T> state => data(
final PaginationErrorWithLoadedDataState<T> state => errorWithData(
state.data,
false,
state.error,
),
},
);
Expand Down
16 changes: 8 additions & 8 deletions lib/src/core/di/injectable.config.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

106 changes: 0 additions & 106 deletions lib/src/data/data_sources/remote/news/news_api_impl.dart

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import 'package:either_dart/either.dart';

import '../../../../core/utils/exception/exception_handler.dart';
import '../../../../domain/models/category_model/category_model.dart';
import '../../../../domain/models/news_model/news_model.dart';
import '../../../../domain/models/result_model/result_model.dart';

abstract class NewsApi {
Future<Either<AppException, ResultModel<NewsModel>>> fetchNews({
abstract class NewsDataSource {
Future<ResultModel<NewsModel>> fetchNews({
required int page,
required int pageSize,
Map<String, dynamic>? params,
Expand Down
93 changes: 93 additions & 0 deletions lib/src/data/data_sources/remote/news/news_data_source_impl.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import 'dart:math';

import 'package:faker/faker.dart';
import 'package:injectable/injectable.dart';

import '../../../../core/utils/exception/exception_handler.dart';
import '../../../../domain/models/category_model/category_model.dart';
import '../../../../domain/models/news_model/news_model.dart';
import '../../../../domain/models/result_model/result_model.dart';
import 'news_data_source.dart';

@Singleton(as: NewsDataSource)
class NewsDataSourceImpl implements NewsDataSource {
final _faker = Faker();
final _totalNewsItems = 100;
final _categories = [
'Technology',
'Health',
'Sports',
'Business',
'Entertainment',
];

@override
Future<ResultModel<NewsModel>> fetchNews({
required int page,
required int pageSize,
Map<String, dynamic>? params,
}) async {
try {
await Future.delayed(const Duration(milliseconds: 500), () {});

final startIndex = page * pageSize;
final endIndex = min(startIndex + pageSize, _totalNewsItems);

if (startIndex >= _totalNewsItems) {
return ResultModel<NewsModel>(
data: [],
count: _totalNewsItems,
);
}

final newsItems = List<NewsModel>.generate(
endIndex - startIndex,
(index) {
final randomCategory = _faker.randomGenerator.element(_categories);

return NewsModel(
title: _faker.lorem.sentence(),
imageUrl: _faker.image.loremPicsum(),
publishedAt: _faker.date.dateTime(),
category: CategoryModel(
name: randomCategory,
id: _faker.randomGenerator.integer(1000),
),
);
},
);

return ResultModel<NewsModel>(
data: newsItems,
count: _totalNewsItems,
);
} catch (error, stackTrace) {
throw ExceptionHandler.handle(
error,
stackTrace: stackTrace,
);
}
}

@override
Future<List<CategoryModel>> fetchCategories() async {
try {
await Future.delayed(const Duration(milliseconds: 100), () {});

final categories = List<CategoryModel>.generate(
_categories.length,
(index) => CategoryModel(
name: _faker.randomGenerator.element(_categories),
id: _faker.randomGenerator.integer(1000),
),
);

return categories;
} catch (error, stackTrace) {
throw ExceptionHandler.handle(
error,
stackTrace: stackTrace,
);
}
}
}
22 changes: 14 additions & 8 deletions lib/src/data/repositories/news_repository_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,31 @@ import '../../domain/models/category_model/category_model.dart';
import '../../domain/models/news_model/news_model.dart';
import '../../domain/models/result_model/result_model.dart';
import '../../domain/repositories/news_repository.dart';
import '../data_sources/remote/news/news_api.dart';
import '../data_sources/remote/news/news_data_source.dart';

@Singleton(as: NewsRepository)
class NewsRepositoryImpl implements NewsRepository {
NewsRepositoryImpl(this._newsApi);

final NewsApi _newsApi;
final NewsDataSource _newsApi;

@override
Future<Either<AppException, ResultModel<NewsModel>>> fetchNews({
required int page,
required int pageSize,
Map<String, dynamic>? params,
}) {
return _newsApi.fetchNews(
page: page,
pageSize: pageSize,
params: params,
);
}) async {
try {
return Right(
await _newsApi.fetchNews(
page: page,
pageSize: pageSize,
params: params,
),
);
} on AppException catch (error) {
return Left(error);
}
}

@override
Expand Down
21 changes: 18 additions & 3 deletions lib/src/presentation/pages/explore_page/explore_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,23 +122,38 @@ class _BuildNewsListState extends State<_BuildNewsList>
@override
Widget build(BuildContext context) {
super.build(context);
const isFirstLarge = true;

return BlocProvider(
create: (context) => newsBloc..initialize(widget.category),
child: BlocBuilder<NewsBloc, NewsState>(
builder: (context, state) {
return state.when(
data: (data, isLoading) {
data: (data) {
return NewsListView(
news: data,
isFirstLarge: true,
isFirstLarge: isFirstLarge,
onItemBuildIndex: newsBloc.onLoadItemAtIndex,
);
},
loading: () => const NewsShimmerListView(
isFirstLarge: true,
isFirstLarge: isFirstLarge,
),
error: ErrorWidget.new,
loadingWithData: (data) {
return NewsListView(
news: data,
isFirstLarge: isFirstLarge,
onItemBuildIndex: newsBloc.onLoadItemAtIndex,
);
},
errorWithData: (data, error) {
return NewsListView(
news: data,
isFirstLarge: isFirstLarge,
onItemBuildIndex: newsBloc.onLoadItemAtIndex,
);
},
);
},
),
Expand Down
Loading