mohsen
1 year ago
33 changed files with 642 additions and 504 deletions
-
15data/data_core/local_db/local_db_core/lib/lib/boxes/box_list/setting_box/app_setting_box.dart
-
1data/data_core/local_db/local_db_core/lib/lib/boxes/box_list/setting_box/box_keys.dart
-
34data/data_core/network/network_core/lib/initializer/gamification_initializer.dart
-
37data/data_core/network/network_core/lib/initializer/hamrah_cloud_initializer.dart
-
39data/data_core/network/network_core/lib/initializer/logger_initializer.dart
-
14data/data_core/network/network_core/lib/network/helper/config.dart
-
132data/data_core/network/network_core/lib/network/networking/api_endpoint.dart
-
5data/data_core/network/network_core/lib/network/networking/api_service.dart
-
14data/data_core/network/network_core/lib/network/networking/interceptors/api_interceptor.dart
-
86data/data_types/data/lib/app_api_data/app_api_repository_impl.dart
-
10data/data_types/data/lib/app_setting_data/repository/app_setting_box_repository_impl.dart
-
2data/data_types/data/pubspec.yaml
-
19domain/repositories/lib/app_api_domain/models/comment_model.dart
-
19domain/repositories/lib/app_api_domain/models/contact_us_model.dart
-
22domain/repositories/lib/app_api_domain/models/login_model.dart
-
13domain/repositories/lib/app_api_domain/models/login_response_model.dart
-
43domain/repositories/lib/app_api_domain/models/post_model.dart
-
19domain/repositories/lib/app_api_domain/models/send_comment_model.dart
-
45domain/repositories/lib/app_api_domain/models/single_post_model.dart
-
23domain/repositories/lib/app_api_domain/repository/app_api_repository.dart
-
4domain/repositories/lib/app_setting_box_domain/repository/app_setting_box_repository.dart
-
45lib/core/select_language/cubit/select_language_cubit.dart
-
16lib/core/utils/app_utils.dart
-
2lib/features/about_us/about_us_screen.dart
-
124lib/features/main/main_screen.dart
-
75lib/features/posts/cubit/posts_cubit.dart
-
44lib/features/posts/screen/posts_screen.dart
-
12lib/features/posts/widgets/post_item_widget.dart
-
19lib/features/single_post/cubit/single_post_cubit.dart
-
27lib/features/single_post/screen/single_post_screen.dart
-
87pubspec.lock
-
3pubspec.yaml
@ -1,34 +0,0 @@ |
|||||
import 'package:dio/dio.dart'; |
|
||||
import 'package:network_core/network/interface/network_initializer_interface.dart'; |
|
||||
import 'package:network_core/network/networking/api_endpoint.dart'; |
|
||||
import 'package:network_core/network/networking/api_service.dart'; |
|
||||
import 'package:network_core/network/networking/dio_service.dart'; |
|
||||
|
|
||||
class GamificationInitializer implements NetworkInitializerInterface { |
|
||||
factory GamificationInitializer() { |
|
||||
return instance; |
|
||||
} |
|
||||
|
|
||||
GamificationInitializer.privateConstructor(); |
|
||||
|
|
||||
static final GamificationInitializer instance = GamificationInitializer.privateConstructor(); |
|
||||
|
|
||||
@override |
|
||||
DioService getDioService() { |
|
||||
return DioService( |
|
||||
dioClient: getDioClient(), |
|
||||
interceptors: [], |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
@override |
|
||||
Dio getDioClient() { |
|
||||
final baseOptions = BaseOptions(baseUrl: ApiEndpoint.gamificationBaseUrl); |
|
||||
return Dio(baseOptions); |
|
||||
} |
|
||||
|
|
||||
@override |
|
||||
ApiService getApiService() { |
|
||||
return ApiService(getDioService()); |
|
||||
} |
|
||||
} |
|
@ -1,37 +0,0 @@ |
|||||
import 'package:dio/dio.dart'; |
|
||||
import 'package:network_core/network/interface/network_initializer_interface.dart'; |
|
||||
import 'package:network_core/network/networking/api_endpoint.dart'; |
|
||||
import 'package:network_core/network/networking/api_service.dart'; |
|
||||
import 'package:network_core/network/networking/dio_service.dart'; |
|
||||
import 'package:network_core/network/networking/interceptors/api_interceptor.dart'; |
|
||||
|
|
||||
class HamrahCloudInitializer implements NetworkInitializerInterface { |
|
||||
factory HamrahCloudInitializer() { |
|
||||
return instance; |
|
||||
} |
|
||||
|
|
||||
HamrahCloudInitializer.privateConstructor(); |
|
||||
|
|
||||
static final HamrahCloudInitializer instance = HamrahCloudInitializer.privateConstructor(); |
|
||||
|
|
||||
@override |
|
||||
DioService getDioService() { |
|
||||
return DioService( |
|
||||
dioClient: getDioClient(), |
|
||||
interceptors: [ |
|
||||
ApiInterceptor(useToken: false, addAllowMethod: false), |
|
||||
], |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
@override |
|
||||
Dio getDioClient() { |
|
||||
final baseOptions = BaseOptions(baseUrl: ApiEndpoint.hamrahCloudBaseUrl); |
|
||||
return Dio(baseOptions); |
|
||||
} |
|
||||
|
|
||||
@override |
|
||||
ApiService getApiService() { |
|
||||
return ApiService(getDioService()); |
|
||||
} |
|
||||
} |
|
@ -1,39 +0,0 @@ |
|||||
import 'package:dio/dio.dart'; |
|
||||
import 'package:network_core/network/interface/network_initializer_interface.dart'; |
|
||||
import 'package:network_core/network/networking/api_endpoint.dart'; |
|
||||
import 'package:network_core/network/networking/api_service.dart'; |
|
||||
import 'package:network_core/network/networking/dio_service.dart'; |
|
||||
import 'package:network_core/network/networking/interceptors/api_interceptor.dart'; |
|
||||
|
|
||||
class LoggerInitializer implements NetworkInitializerInterface { |
|
||||
factory LoggerInitializer() { |
|
||||
return instance; |
|
||||
} |
|
||||
|
|
||||
LoggerInitializer.privateConstructor(); |
|
||||
|
|
||||
static final LoggerInitializer instance = LoggerInitializer.privateConstructor(); |
|
||||
|
|
||||
@override |
|
||||
DioService getDioService() { |
|
||||
return DioService( |
|
||||
dioClient: getDioClient(), |
|
||||
interceptors: [ |
|
||||
ApiInterceptor(), |
|
||||
], |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
@override |
|
||||
Dio getDioClient() { |
|
||||
final baseOptions = BaseOptions( |
|
||||
baseUrl: ApiEndpoint.loggerBaseUrl, |
|
||||
); |
|
||||
return Dio(baseOptions); |
|
||||
} |
|
||||
|
|
||||
@override |
|
||||
ApiService getApiService() { |
|
||||
return ApiService(getDioService()); |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,86 @@ |
|||||
|
import 'package:network_core/network/networking/api_endpoint.dart'; |
||||
|
import 'package:network_core/network/networking/api_service.dart'; |
||||
|
import 'package:repositories/app_api_domain/models/login_response_model.dart'; |
||||
|
import 'package:repositories/app_api_domain/models/post_model.dart'; |
||||
|
import 'package:repositories/app_api_domain/models/single_post_model.dart'; |
||||
|
import 'package:repositories/app_api_domain/repository/app_api_repository.dart'; |
||||
|
|
||||
|
class AppApiRepositoryImpl implements AppApiRepository { |
||||
|
final ApiService _apiService; |
||||
|
|
||||
|
AppApiRepositoryImpl({required ApiService apiService}) : _apiService = apiService; |
||||
|
|
||||
|
@override |
||||
|
Future<void> contactUs({required Map<String, dynamic> data}) async { |
||||
|
return await _apiService.setData( |
||||
|
endpoint: ApiEndpoint.api(AppEndpoint.contactUs), |
||||
|
converter: (response) {}, |
||||
|
data: data, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
Future<List<PostModel>> getPostList({ |
||||
|
required String catId, |
||||
|
required String sort, |
||||
|
required int page, |
||||
|
required String languageCode, |
||||
|
}) async { |
||||
|
return await _apiService.getCollectionData( |
||||
|
endpoint: |
||||
|
'${ApiEndpoint.api(AppEndpoint.postList)}?cat=$catId&sort=$sort&page=$page&language_code=$languageCode', |
||||
|
converter: (response) { |
||||
|
return List<PostModel>.from( |
||||
|
response.data['data'].map((game) { |
||||
|
return PostModel.fromJson(game); |
||||
|
}), |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
Future<SinglePostModel> getSinglePost({required int postId}) async { |
||||
|
return await _apiService.getDocumentData<SinglePostModel>( |
||||
|
endpoint: '${ApiEndpoint.api(AppEndpoint.singlePost)}?post=$postId', |
||||
|
converter: (response) { |
||||
|
return SinglePostModel.fromJson(response); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
Future<LoginResponseModel> login({required Map<String, dynamic> data}) async { |
||||
|
return await _apiService.setData<LoginResponseModel>( |
||||
|
endpoint: ApiEndpoint.api(AppEndpoint.login), |
||||
|
converter: (response) { |
||||
|
return LoginResponseModel.fromJson(response.data); |
||||
|
}, |
||||
|
queryParams: data, |
||||
|
requiresAuthToken: false, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
Future<List<PostModel>> searchPost({required String query, required String languageCode}) async { |
||||
|
return await _apiService.getCollectionData<List<PostModel>>( |
||||
|
endpoint: '${ApiEndpoint.api(AppEndpoint.search)}/?s=$query&language_code=$languageCode', |
||||
|
converter: (response) { |
||||
|
return List<PostModel>.from( |
||||
|
response.data.map((game) { |
||||
|
return PostModel.fromJson(game); |
||||
|
}), |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
Future<void> sendComment({required Map<String, dynamic> data}) async { |
||||
|
return await _apiService.setData( |
||||
|
endpoint: ApiEndpoint.api(AppEndpoint.sendComment), |
||||
|
converter: (response) {}, |
||||
|
data: data, |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
class CommentModel { |
||||
|
final String fullName; |
||||
|
final String createdDate; |
||||
|
final String text; |
||||
|
|
||||
|
const CommentModel({ |
||||
|
required this.text, |
||||
|
required this.createdDate, |
||||
|
required this.fullName, |
||||
|
}); |
||||
|
|
||||
|
factory CommentModel.fromJson(Map<String, dynamic> json) { |
||||
|
return CommentModel( |
||||
|
text: json['text'], |
||||
|
createdDate: json['created_date'], |
||||
|
fullName: json['full_name'], |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
class ContactUsModel { |
||||
|
final String email; |
||||
|
final String text; |
||||
|
final String fullName; |
||||
|
|
||||
|
const ContactUsModel({ |
||||
|
required this.text, |
||||
|
required this.fullName, |
||||
|
required this.email, |
||||
|
}); |
||||
|
|
||||
|
Map<String, dynamic> toJson() { |
||||
|
return { |
||||
|
'email': email, |
||||
|
'full_name': fullName, |
||||
|
'text': text, |
||||
|
}; |
||||
|
} |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
class LoginModel { |
||||
|
final String language; |
||||
|
final String mobileDeviceId; |
||||
|
final String timeZone; |
||||
|
final String apiVersion; |
||||
|
|
||||
|
const LoginModel({ |
||||
|
required this.language, |
||||
|
required this.apiVersion, |
||||
|
required this.mobileDeviceId, |
||||
|
required this.timeZone, |
||||
|
}); |
||||
|
|
||||
|
Map<String, dynamic> toJson() { |
||||
|
return { |
||||
|
'language': language, |
||||
|
'mobile_device_id': mobileDeviceId, |
||||
|
'timezone': timeZone, |
||||
|
'api_version': apiVersion, |
||||
|
}; |
||||
|
} |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
class LoginResponseModel { |
||||
|
final String token; |
||||
|
|
||||
|
const LoginResponseModel({required this.token}); |
||||
|
|
||||
|
factory LoginResponseModel.fromJson(Map<String, dynamic> json) { |
||||
|
return LoginResponseModel(token: json['token']); |
||||
|
} |
||||
|
|
||||
|
Map<String, dynamic> toJson() { |
||||
|
return {'token': token}; |
||||
|
} |
||||
|
} |
@ -0,0 +1,43 @@ |
|||||
|
class PostModel { |
||||
|
final int id; |
||||
|
final String title; |
||||
|
final String content; |
||||
|
final String summary; |
||||
|
final String publishDate; |
||||
|
final String? thumbnail; |
||||
|
final String languageCode; |
||||
|
final int viewCount; |
||||
|
final int commentCount; |
||||
|
final String websiteUrl; |
||||
|
final bool isPinned; |
||||
|
|
||||
|
const PostModel({ |
||||
|
required this.title, |
||||
|
required this.viewCount, |
||||
|
required this.commentCount, |
||||
|
required this.websiteUrl, |
||||
|
required this.content, |
||||
|
required this.id, |
||||
|
required this.summary, |
||||
|
required this.isPinned, |
||||
|
required this.languageCode, |
||||
|
required this.publishDate, |
||||
|
required this.thumbnail, |
||||
|
}); |
||||
|
|
||||
|
factory PostModel.fromJson(Map<String, dynamic> json) { |
||||
|
return PostModel( |
||||
|
id: json['id'], |
||||
|
title: json['title'], |
||||
|
content: json['content'], |
||||
|
commentCount: json['comm_count'], |
||||
|
viewCount: json['view_count'], |
||||
|
summary: json['summery'], |
||||
|
publishDate: json['publish_date'][0], |
||||
|
websiteUrl: json['website_url'], |
||||
|
thumbnail: json['thumbnail'] ?? '', |
||||
|
languageCode: json['language_code']['slug'], |
||||
|
isPinned: json['is_pinned'], |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
class SendCommentModel { |
||||
|
final int postId; |
||||
|
final String text; |
||||
|
final String fullName; |
||||
|
|
||||
|
const SendCommentModel({ |
||||
|
required this.text, |
||||
|
required this.fullName, |
||||
|
required this.postId, |
||||
|
}); |
||||
|
|
||||
|
Map<String, dynamic> toJson() { |
||||
|
return { |
||||
|
'post_id': postId, |
||||
|
'full_name': fullName, |
||||
|
'text': text, |
||||
|
}; |
||||
|
} |
||||
|
} |
@ -0,0 +1,45 @@ |
|||||
|
import 'package:repositories/app_api_domain/models/comment_model.dart'; |
||||
|
|
||||
|
class SinglePostModel { |
||||
|
final int id; |
||||
|
final String title; |
||||
|
final String summary; |
||||
|
final String publishDate; |
||||
|
final String? thumbnail; |
||||
|
final String languageCode; |
||||
|
final String websiteUrl; |
||||
|
final int viewCount; |
||||
|
final int commentCount; |
||||
|
final List<CommentModel> comments; |
||||
|
final String content; |
||||
|
|
||||
|
const SinglePostModel({ |
||||
|
required this.title, |
||||
|
required this.websiteUrl, |
||||
|
required this.content, |
||||
|
required this.id, |
||||
|
required this.comments, |
||||
|
required this.summary, |
||||
|
required this.languageCode, |
||||
|
required this.publishDate, |
||||
|
required this.thumbnail, |
||||
|
required this.commentCount, |
||||
|
required this.viewCount, |
||||
|
}); |
||||
|
|
||||
|
factory SinglePostModel.fromJson(Map<String, dynamic> json) { |
||||
|
return SinglePostModel( |
||||
|
id: json['id'], |
||||
|
websiteUrl: json['website_url'], |
||||
|
title: json['title'], |
||||
|
content: json['content'], |
||||
|
summary: json['summery'], |
||||
|
publishDate: json['publish_date'][0], |
||||
|
thumbnail: json['thumbnail'], |
||||
|
languageCode: json['language_code']['slug'], |
||||
|
comments: List<CommentModel>.from(json['comments'].map((post) => CommentModel.fromJson(post))), |
||||
|
commentCount: json['comm_count'], |
||||
|
viewCount: json['view_count'], |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
import 'package:repositories/app_api_domain/models/login_response_model.dart'; |
||||
|
import 'package:repositories/app_api_domain/models/post_model.dart'; |
||||
|
import 'package:repositories/app_api_domain/models/single_post_model.dart'; |
||||
|
import 'package:repositories/typedefs.dart'; |
||||
|
|
||||
|
abstract class AppApiRepository { |
||||
|
Future<LoginResponseModel> login({required JSON data}); |
||||
|
|
||||
|
Future<List<PostModel>> getPostList({ |
||||
|
required String catId, |
||||
|
required String sort, |
||||
|
required int page, |
||||
|
required String languageCode, |
||||
|
}); |
||||
|
|
||||
|
Future<SinglePostModel> getSinglePost({required int postId}); |
||||
|
|
||||
|
Future<void> sendComment({required JSON data}); |
||||
|
|
||||
|
Future<List<PostModel>> searchPost({required String query, required String languageCode}); |
||||
|
|
||||
|
Future<void> contactUs({required JSON data}); |
||||
|
} |
@ -1,34 +1,63 @@ |
|||||
|
import 'package:data/app_api_data/app_api_repository_impl.dart'; |
||||
|
import 'package:data/app_setting_data/repository/app_setting_box_repository_impl.dart'; |
||||
import 'package:flutter_bloc/flutter_bloc.dart'; |
import 'package:flutter_bloc/flutter_bloc.dart'; |
||||
import 'package:sonnat/core/language/language_cubit.dart'; |
|
||||
|
import 'package:local_db_core/lib/boxes/box_list/setting_box/app_setting_box.dart'; |
||||
|
import 'package:network_core/initializer/base_initializer.dart'; |
||||
|
import 'package:network_core/network/networking/custom_exception.dart'; |
||||
|
import 'package:repositories/app_api_domain/models/login_model.dart'; |
||||
|
import 'package:repositories/app_api_domain/models/login_response_model.dart'; |
||||
|
import 'package:repositories/app_api_domain/repository/app_api_repository.dart'; |
||||
|
import 'package:repositories/app_setting_box_domain/repository/app_setting_box_repository.dart'; |
||||
import 'package:sonnat/core/language/languages.dart'; |
import 'package:sonnat/core/language/languages.dart'; |
||||
import 'package:sonnat/core/language/translator.dart'; |
import 'package:sonnat/core/language/translator.dart'; |
||||
|
import 'package:sonnat/core/utils/app_utils.dart'; |
||||
import 'package:sonnat/core/utils/base_cubit_type.dart'; |
import 'package:sonnat/core/utils/base_cubit_type.dart'; |
||||
|
|
||||
class SelectLanguageCubit extends Cubit<BaseCubitType<SelectLanguageState>> { |
class SelectLanguageCubit extends Cubit<BaseCubitType<SelectLanguageState>> { |
||||
|
final AppSettingBoxRepository _repository = AppSettingBoxRepositoryImpl(appSettingBox: AppSettingBox()); |
||||
|
final AppApiRepository _remoteRepository = AppApiRepositoryImpl(apiService: BaseInitializer.instance.getApiService()); |
||||
|
|
||||
SelectLanguageCubit() : super(BaseCubitType(eventName: SelectLanguageState.empty)); |
SelectLanguageCubit() : super(BaseCubitType(eventName: SelectLanguageState.empty)); |
||||
|
|
||||
void empty() => emit(BaseCubitType(eventName: SelectLanguageState.empty)); |
void empty() => emit(BaseCubitType(eventName: SelectLanguageState.empty)); |
||||
|
|
||||
Future<void> selectLanguage(String language) async { |
|
||||
|
void selectLanguage(String language) { |
||||
switch (language) { |
switch (language) { |
||||
case 'fa': |
case 'fa': |
||||
await Translator.setNewLanguage(Languages.fa); |
|
||||
emit(BaseCubitType(eventName: SelectLanguageState.loaded, data: language)); |
|
||||
|
login(Languages.fa); |
||||
return; |
return; |
||||
case 'en': |
case 'en': |
||||
await Translator.setNewLanguage(Languages.en); |
|
||||
emit(BaseCubitType(eventName: SelectLanguageState.loaded, data: language)); |
|
||||
|
login(Languages.en); |
||||
return; |
return; |
||||
case 'ar': |
case 'ar': |
||||
await Translator.setNewLanguage(Languages.ar); |
|
||||
emit(BaseCubitType(eventName: SelectLanguageState.loaded, data: language)); |
|
||||
|
login(Languages.ar); |
||||
return; |
return; |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
|
Future<void> login(Languages newLanguage) async { |
||||
|
await Translator.setNewLanguage(newLanguage); |
||||
|
await _repository.setCurrentLanguage(newLanguage.value); |
||||
|
String? deviceId = await Utils.instance.getId(); |
||||
|
deviceId ??= 'user-device'; |
||||
|
LoginModel loginModel = LoginModel( |
||||
|
language: newLanguage.value, |
||||
|
apiVersion: '1', |
||||
|
mobileDeviceId: deviceId, |
||||
|
timeZone: '${DateTime.now().timeZoneOffset.inHours}:${DateTime.now().timeZoneOffset.inMinutes}', |
||||
|
); |
||||
|
try { |
||||
|
LoginResponseModel responseModel = await _remoteRepository.login(data: loginModel.toJson()); |
||||
|
await _repository.setUserToken(responseModel.toJson()); |
||||
|
emit(BaseCubitType(eventName: SelectLanguageState.loaded, data: newLanguage.value)); |
||||
|
} on CustomException { |
||||
|
emit(BaseCubitType(eventName: SelectLanguageState.error)); |
||||
|
} |
||||
|
} |
||||
} |
} |
||||
|
|
||||
enum SelectLanguageState { |
enum SelectLanguageState { |
||||
empty, |
empty, |
||||
loaded, |
loaded, |
||||
|
error, |
||||
} |
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue