Skip to content

Commit 61c7dfa

Browse files
authored
Merge pull request #7 from CoderJava/implement-tdd
Create Class Model Category News
2 parents 6ccfec5 + 1cab34d commit 61c7dfa

19 files changed

+424
-28
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,6 @@ lib/generated_plugin_registrant.dart
3434

3535
# Exceptions to above rules.
3636
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
37+
38+
# Code coverage directory
39+
coverage/

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
[![Codemagic build status](https://api.codemagic.io/apps/5e93249b1838ac3d3e52a5bc/5e93249b1838ac3d3e52a5bb/status_badge.svg)](https://codemagic.io/apps/5e93249b1838ac3d3e52a5bc/5e93249b1838ac3d3e52a5bb/latest_build)
2+
[![codecov](https://codecov.io/gh/CoderJava/Flutter-News-App/branch/dev-v2.0.0/graph/badge.svg)](https://codecov.io/gh/CoderJava/Flutter-News-App)
3+
[![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://github.com/tenhobi/effective_dart)
4+
15
# Flutter News App
26
News App developed with Flutter and API from [News API](https://newsapi.org)
37

codemagic.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Automatically generated on 2020-04-12 UTC from https://codemagic.io/app/5e93249b1838ac3d3e52a5bc/settings
2+
# Note that this configuration is not an exact match to UI settings. Review and adjust as necessary.
3+
4+
workflows:
5+
default-workflow:
6+
name: Default Workflow
7+
environment:
8+
vars:
9+
CODECOV_TOKEN: Encrypted(Z0FBQUFBQmVrMGRUSGRXRFVweTVGYUIzMThqbGNkNW5aSHE3SnYyeHg4amk3NEF4ZGVwakdXSFBmQVVoRmczZk9GaHdCakhORWcxMUtwZFVYeXJCSHhjWUNiZWM2d2tCUUpfWGwxSjZCaEhfUXlzOS1GN3VRRmdWanlNYnNxTmlleExZak5iWEFLTm0=)
10+
flutter: stable
11+
xcode: latest
12+
cocoapods: default
13+
triggering:
14+
events:
15+
- push
16+
branch_patterns:
17+
- pattern: '*'
18+
include: true
19+
source: true
20+
scripts:
21+
- flutter packages pub get
22+
- |
23+
#!/bin/sh
24+
flutter test --coverage
25+
- flutter test
26+
- |
27+
#!/bin/bash
28+
echo $CODECOV_TOKEN > .cc_token
29+
bash <(curl -s https://codecov.io/bash) -t @.cc_token
30+
artifacts:
31+
- flutter_drive.log
32+
publishing:
33+
email:
34+
recipients:
35+

lib/core/error/exception.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class CacheException implements Exception {}
2+
3+
class ConnectionException implements Exception {}

lib/core/error/failure.dart

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import 'package:equatable/equatable.dart';
2+
3+
abstract class Failure extends Equatable {}
4+
5+
final String messageConnectionFailure = 'messageConnectionFailure';
6+
7+
class ServerFailure extends Failure {
8+
final String errorMessage;
9+
10+
ServerFailure(this.errorMessage);
11+
12+
@override
13+
List<Object> get props => [errorMessage];
14+
15+
@override
16+
String toString() {
17+
return 'ServerFailure{errorMessage: $errorMessage}';
18+
}
19+
}
20+
21+
class CacheFailure extends Failure {
22+
final String errorMessage;
23+
24+
CacheFailure(this.errorMessage);
25+
26+
@override
27+
List<Object> get props => [errorMessage];
28+
29+
@override
30+
String toString() {
31+
return 'CacheFailure{errorMessage: $errorMessage}';
32+
}
33+
}
34+
35+
class ConnectionFailure extends Failure {
36+
final String errorMessage = messageConnectionFailure;
37+
38+
@override
39+
List<Object> get props => [errorMessage];
40+
41+
@override
42+
String toString() {
43+
return 'ConnectionFailure{errorMessage: $errorMessage}';
44+
}
45+
}

lib/core/network/network_info.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import 'package:data_connection_checker/data_connection_checker.dart';
2+
3+
abstract class NetworkInfo {
4+
Future<bool> get isConnected;
5+
}
6+
7+
class NetworkInfoImpl implements NetworkInfo {
8+
final DataConnectionChecker dataConnectionChecker;
9+
10+
NetworkInfoImpl(this.dataConnectionChecker);
11+
12+
@override
13+
Future<bool> get isConnected => dataConnectionChecker.hasConnection;
14+
}

lib/core/usecase/usecase.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import 'package:dartz/dartz.dart';
2+
import 'package:equatable/equatable.dart';
3+
import 'package:flutter_news_app/core/error/failure.dart';
4+
5+
abstract class UseCase<Type, Params> {
6+
Future<Either<Failure, Type>> call(Params params);
7+
}
8+
9+
class NoParams extends Equatable {
10+
@override
11+
List<Object> get props => [];
12+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import 'package:dio/dio.dart';
2+
import 'package:flutter_news_app/config/flavor_config.dart';
3+
4+
class DioLoggingInterceptor extends InterceptorsWrapper {
5+
@override
6+
Future onRequest(RequestOptions options) async {
7+
if (FlavorConfig.instance.flavor == Flavor.DEVELOPMENT) {
8+
print("--> ${options.method != null ? options.method.toUpperCase() : 'METHOD'} ${"" + (options.baseUrl ?? "") + (options.path ?? "")}");
9+
print('Headers:');
10+
options.headers.forEach((k, v) => print('$k: $v'));
11+
if (options.queryParameters != null) {
12+
print('queryParameters:');
13+
options.queryParameters.forEach((k, v) => print('$k: $v'));
14+
}
15+
if (options.data != null) {
16+
print('Body: ${options.data}');
17+
}
18+
print("--> END ${options.method != null ? options.method.toUpperCase() : 'METHOD'}");
19+
}
20+
21+
// example for add header authorization
22+
/*if (options.headers.containsKey(requiredToken)) {
23+
options.headers.remove(requiredToken);
24+
options.headers.addAll({'Authorization': 'Bearer $token'});
25+
}*/
26+
return options;
27+
}
28+
29+
@override
30+
Future onResponse(Response response) {
31+
if (FlavorConfig.instance.flavor == Flavor.DEVELOPMENT) {
32+
print("<-- ${response.statusCode} ${(response.request != null ? (response.request.baseUrl + response.request.path) : 'URL')}");
33+
print('Headers:');
34+
response.headers?.forEach((k, v) => print('$k: $v'));
35+
print('Response: ${response.data}');
36+
print('<-- END HTTP');
37+
}
38+
return super.onResponse(response);
39+
}
40+
41+
@override
42+
Future onError(DioError dioError) async {
43+
if (FlavorConfig.instance.flavor == Flavor.DEVELOPMENT) {
44+
print(
45+
"<-- ${dioError.message} ${(dioError.response?.request != null ? (dioError.response.request.baseUrl + dioError.response.request.path) : 'URL')}");
46+
print("${dioError.response != null ? dioError.response.data : 'Unknown Error'}");
47+
print('<-- End error');
48+
}
49+
return super.onError(dioError);
50+
}
51+
}

lib/core/util/util.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export 'dio_logging_interceptor.dart';
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import 'package:equatable/equatable.dart';
2+
import 'package:json_annotation/json_annotation.dart';
3+
import 'package:meta/meta.dart';
4+
5+
part 'category_news_model.g.dart';
6+
7+
@JsonSerializable()
8+
class CategoryNewsModel extends Equatable {
9+
final String image;
10+
final String title;
11+
12+
CategoryNewsModel({
13+
@required this.image,
14+
@required this.title,
15+
});
16+
17+
factory CategoryNewsModel.fromJson(Map<String, dynamic> json) => _$CategoryNewsModelFromJson(json);
18+
19+
Map<String, dynamic> toJson() => _$CategoryNewsModelToJson(this);
20+
21+
@override
22+
List<Object> get props => [image, title];
23+
24+
@override
25+
String toString() {
26+
return 'CategoryNewsModel{image: $image, title: $title}';
27+
}
28+
}

0 commit comments

Comments
 (0)