mohsen
1 year ago
33 changed files with 642 additions and 504 deletions
-
17data/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
-
22data/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
-
170lib/features/main/main_screen.dart
-
77lib/features/posts/cubit/posts_cubit.dart
-
80lib/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
-
2lib/features/splash/cubit/splash_cubit.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: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/translator.dart'; |
|||
import 'package:sonnat/core/utils/app_utils.dart'; |
|||
import 'package:sonnat/core/utils/base_cubit_type.dart'; |
|||
|
|||
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)); |
|||
|
|||
void empty() => emit(BaseCubitType(eventName: SelectLanguageState.empty)); |
|||
|
|||
Future<void> selectLanguage(String language) async { |
|||
void selectLanguage(String language) { |
|||
switch (language) { |
|||
case 'fa': |
|||
await Translator.setNewLanguage(Languages.fa); |
|||
emit(BaseCubitType(eventName: SelectLanguageState.loaded, data: language)); |
|||
login(Languages.fa); |
|||
return; |
|||
case 'en': |
|||
await Translator.setNewLanguage(Languages.en); |
|||
emit(BaseCubitType(eventName: SelectLanguageState.loaded, data: language)); |
|||
login(Languages.en); |
|||
return; |
|||
case 'ar': |
|||
await Translator.setNewLanguage(Languages.ar); |
|||
emit(BaseCubitType(eventName: SelectLanguageState.loaded, data: language)); |
|||
login(Languages.ar); |
|||
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 { |
|||
empty, |
|||
loaded, |
|||
error, |
|||
} |