Merge pull request 'main' (#5) from eatvio/eatvio_app:main into main

Reviewed-on: mso7nueh/eatvio_app#5
This commit is contained in:
mso7nueh
2024-11-15 12:40:41 +00:00
45 changed files with 2177 additions and 1005 deletions

4
assets/icons/eye2.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg width="16" height="10" viewBox="0 0 16 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.21875 0.253125C4.6625 0.509375 2.32188 1.875 0.4125 4.22813C0.028125 4.7 0 4.75625 0 5.00938C0 5.24687 0.046875 5.32812 0.48125 5.85625C2.56562 8.39062 5.22813 9.78125 8 9.78125C10.8063 9.78125 13.4781 8.36875 15.5875 5.77187C15.9719 5.3 16 5.24375 16 4.99062C16 4.75312 15.9531 4.67188 15.5188 4.14375C13.4156 1.58437 10.7312 0.196875 7.94063 0.221875C7.69063 0.224999 7.36562 0.2375 7.21875 0.253125ZM8.70625 1.73125C9.80937 1.96875 10.7344 2.77812 11.1406 3.85625C11.2875 4.24687 11.325 4.475 11.3219 5.01562C11.3219 5.45625 11.3125 5.55312 11.2406 5.81875C10.925 7.00312 10.0031 7.925 8.81875 8.24063C8.55313 8.3125 8.45625 8.32187 8.01562 8.32187C7.475 8.325 7.24688 8.2875 6.85625 8.14062C5.77813 7.73438 4.98438 6.825 4.72813 5.70625C4.64687 5.35313 4.65625 4.59062 4.74375 4.24062C5.07812 2.90937 6.09063 1.95937 7.45 1.7C7.72813 1.64687 8.4 1.6625 8.70625 1.73125Z" fill="#A3A3A3"/>
<path d="M7.45312 3.2625C7.13125 3.36875 6.94688 3.48438 6.70312 3.73438C6.35 4.09063 6.1875 4.49062 6.1875 5C6.1875 5.525 6.35 5.91875 6.71562 6.28438C7.08125 6.65 7.475 6.8125 8 6.8125C8.50938 6.8125 8.90937 6.65 9.26562 6.29688C9.64688 5.92188 9.8125 5.53125 9.8125 5.00312C9.8125 4.83438 9.79063 4.62188 9.76562 4.52187C9.60625 3.90937 9.09063 3.39375 8.47813 3.23438C8.19688 3.1625 7.71875 3.175 7.45312 3.2625Z" fill="#A3A3A3"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

3
assets/icons/filter2.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="25" height="17" viewBox="0 0 25 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.2083 16.25C10.8424 16.25 10.5356 16.1262 10.288 15.8786C10.0405 15.6311 9.91667 15.3243 9.91667 14.9583C9.91667 14.5924 10.0405 14.2856 10.288 14.038C10.5356 13.7905 10.8424 13.6667 11.2083 13.6667H13.7917C14.1576 13.6667 14.4644 13.7905 14.712 14.038C14.9595 14.2856 15.0833 14.5924 15.0833 14.9583C15.0833 15.3243 14.9595 15.6311 14.712 15.8786C14.4644 16.1262 14.1576 16.25 13.7917 16.25H11.2083ZM6.04167 9.79167C5.67569 9.79167 5.36892 9.66788 5.12135 9.42031C4.87378 9.17274 4.75 8.86597 4.75 8.5C4.75 8.13403 4.87378 7.82726 5.12135 7.57969C5.36892 7.33212 5.67569 7.20833 6.04167 7.20833H18.9583C19.3243 7.20833 19.6311 7.33212 19.8786 7.57969C20.1262 7.82726 20.25 8.13403 20.25 8.5C20.25 8.86597 20.1262 9.17274 19.8786 9.42031C19.6311 9.66788 19.3243 9.79167 18.9583 9.79167H6.04167ZM2.16667 3.33333C1.80069 3.33333 1.49392 3.20955 1.24635 2.96198C0.998785 2.71441 0.875 2.40764 0.875 2.04167C0.875 1.67569 0.998785 1.36892 1.24635 1.12135C1.49392 0.873785 1.80069 0.75 2.16667 0.75H22.8333C23.1993 0.75 23.5061 0.873785 23.7536 1.12135C24.0012 1.36892 24.125 1.67569 24.125 2.04167C24.125 2.40764 24.0012 2.71441 23.7536 2.96198C23.5061 3.20955 23.1993 3.33333 22.8333 3.33333H2.16667Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

3
assets/icons/repost.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="16" height="13" viewBox="0 0 16 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.63752 0.25246C8.57688 0.283273 8.49841 0.334627 8.4663 0.368864C8.32005 0.526351 8.30935 0.635907 8.30579 2.08753V3.48094L8.1203 3.49806C8.01685 3.50833 7.73863 3.5323 7.5032 3.55284C5.38794 3.74799 3.56518 4.50803 2.29531 5.72684C1.13959 6.8361 0.426183 8.31853 0.133685 10.2118C0.0516433 10.7562 -0.0268316 11.9339 0.00883882 12.153C0.0552104 12.4406 0.279934 12.6255 0.583133 12.6255C0.836393 12.6255 0.957673 12.5501 1.21093 12.2386C1.54267 11.8278 2.20971 11.2047 2.59851 10.941C3.83628 10.0988 5.03837 9.80439 7.51033 9.72907L8.30222 9.7051L8.31292 11.1567C8.32362 12.7624 8.32005 12.7384 8.55904 12.9028C8.72313 13.0158 9.01563 13.0329 9.17614 12.9404C9.34023 12.848 15.5754 7.56876 15.7217 7.39758C16.0998 6.95593 16.0926 6.22327 15.7003 5.7782C15.5719 5.62756 9.33666 0.351746 9.19041 0.266155C9.04773 0.183988 8.79804 0.17714 8.63752 0.25246ZM12.2759 4.37109C13.9631 5.79874 14.8335 6.55879 14.8335 6.59987C14.8335 6.64438 13.9274 7.43181 12.1689 8.92109L9.50074 11.1807L9.48291 10.1125C9.46507 9.07173 9.46151 9.04434 9.38303 8.91767C9.33666 8.8492 9.22252 8.74649 9.13334 8.69513L8.96569 8.60269L7.89558 8.60612C5.96937 8.61639 4.87785 8.74649 3.7578 9.10597C2.97305 9.35589 2.13836 9.80096 1.5498 10.2803C1.41782 10.3864 1.30368 10.4686 1.29654 10.4617C1.28941 10.4549 1.30724 10.3214 1.33578 10.1604C1.8637 7.16477 3.70786 5.35367 6.80763 4.78877C7.31415 4.69976 7.75289 4.65182 8.41993 4.61759C8.95499 4.59362 8.99066 4.58678 9.14761 4.49091C9.25819 4.42587 9.34736 4.33685 9.40087 4.24099C9.48291 4.09377 9.48291 4.07323 9.48291 3.04272V1.99851L9.60062 2.10464C9.66126 2.15942 10.8669 3.18309 12.2759 4.37109Z" fill="#6D6D6D"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -147,9 +147,14 @@ class AppRouter {
GoRoute(
path: '/about-diet-screen',
name: 'aboutDietScreen',
builder: (context, state) => AboutDietScreen(
diet: state.extra as Diet,
),
builder: (context, state) {
final data = state.extra as Map<String, dynamic>;
return AboutDietScreen(
diet: data['diet'] as Diet,
index: data['index'] as int,
navigateToComments: data['navigateToComments'] as bool,
);
},
),
GoRoute(
path: '/blog-post-create-screen',

View File

@@ -0,0 +1,14 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'diet_likes_model.freezed.dart';
part 'diet_likes_model.g.dart';
@freezed
class DietLikesModel with _$DietLikesModel {
const factory DietLikesModel({
@JsonKey(name: 'total_likers') required int totalLikes,
@JsonKey(name: 'is_liked') required bool isLiked,
}) = _DietLikesModel;
factory DietLikesModel.fromJson(Map<String, Object?> json) => _$DietLikesModelFromJson(json);
}

View File

@@ -0,0 +1,197 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'diet_likes_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
DietLikesModel _$DietLikesModelFromJson(Map<String, dynamic> json) {
return _DietLikesModel.fromJson(json);
}
/// @nodoc
mixin _$DietLikesModel {
@JsonKey(name: 'total_likers')
int get totalLikes => throw _privateConstructorUsedError;
@JsonKey(name: 'is_liked')
bool get isLiked => throw _privateConstructorUsedError;
/// Serializes this DietLikesModel to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of DietLikesModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$DietLikesModelCopyWith<DietLikesModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $DietLikesModelCopyWith<$Res> {
factory $DietLikesModelCopyWith(
DietLikesModel value, $Res Function(DietLikesModel) then) =
_$DietLikesModelCopyWithImpl<$Res, DietLikesModel>;
@useResult
$Res call(
{@JsonKey(name: 'total_likers') int totalLikes,
@JsonKey(name: 'is_liked') bool isLiked});
}
/// @nodoc
class _$DietLikesModelCopyWithImpl<$Res, $Val extends DietLikesModel>
implements $DietLikesModelCopyWith<$Res> {
_$DietLikesModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of DietLikesModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? totalLikes = null,
Object? isLiked = null,
}) {
return _then(_value.copyWith(
totalLikes: null == totalLikes
? _value.totalLikes
: totalLikes // ignore: cast_nullable_to_non_nullable
as int,
isLiked: null == isLiked
? _value.isLiked
: isLiked // ignore: cast_nullable_to_non_nullable
as bool,
) as $Val);
}
}
/// @nodoc
abstract class _$$DietLikesModelImplCopyWith<$Res>
implements $DietLikesModelCopyWith<$Res> {
factory _$$DietLikesModelImplCopyWith(_$DietLikesModelImpl value,
$Res Function(_$DietLikesModelImpl) then) =
__$$DietLikesModelImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{@JsonKey(name: 'total_likers') int totalLikes,
@JsonKey(name: 'is_liked') bool isLiked});
}
/// @nodoc
class __$$DietLikesModelImplCopyWithImpl<$Res>
extends _$DietLikesModelCopyWithImpl<$Res, _$DietLikesModelImpl>
implements _$$DietLikesModelImplCopyWith<$Res> {
__$$DietLikesModelImplCopyWithImpl(
_$DietLikesModelImpl _value, $Res Function(_$DietLikesModelImpl) _then)
: super(_value, _then);
/// Create a copy of DietLikesModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? totalLikes = null,
Object? isLiked = null,
}) {
return _then(_$DietLikesModelImpl(
totalLikes: null == totalLikes
? _value.totalLikes
: totalLikes // ignore: cast_nullable_to_non_nullable
as int,
isLiked: null == isLiked
? _value.isLiked
: isLiked // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// @nodoc
@JsonSerializable()
class _$DietLikesModelImpl implements _DietLikesModel {
const _$DietLikesModelImpl(
{@JsonKey(name: 'total_likers') required this.totalLikes,
@JsonKey(name: 'is_liked') required this.isLiked});
factory _$DietLikesModelImpl.fromJson(Map<String, dynamic> json) =>
_$$DietLikesModelImplFromJson(json);
@override
@JsonKey(name: 'total_likers')
final int totalLikes;
@override
@JsonKey(name: 'is_liked')
final bool isLiked;
@override
String toString() {
return 'DietLikesModel(totalLikes: $totalLikes, isLiked: $isLiked)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$DietLikesModelImpl &&
(identical(other.totalLikes, totalLikes) ||
other.totalLikes == totalLikes) &&
(identical(other.isLiked, isLiked) || other.isLiked == isLiked));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, totalLikes, isLiked);
/// Create a copy of DietLikesModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$DietLikesModelImplCopyWith<_$DietLikesModelImpl> get copyWith =>
__$$DietLikesModelImplCopyWithImpl<_$DietLikesModelImpl>(
this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$DietLikesModelImplToJson(
this,
);
}
}
abstract class _DietLikesModel implements DietLikesModel {
const factory _DietLikesModel(
{@JsonKey(name: 'total_likers') required final int totalLikes,
@JsonKey(name: 'is_liked') required final bool isLiked}) =
_$DietLikesModelImpl;
factory _DietLikesModel.fromJson(Map<String, dynamic> json) =
_$DietLikesModelImpl.fromJson;
@override
@JsonKey(name: 'total_likers')
int get totalLikes;
@override
@JsonKey(name: 'is_liked')
bool get isLiked;
/// Create a copy of DietLikesModel
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$DietLikesModelImplCopyWith<_$DietLikesModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -0,0 +1,20 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'diet_likes_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$DietLikesModelImpl _$$DietLikesModelImplFromJson(Map<String, dynamic> json) =>
_$DietLikesModelImpl(
totalLikes: (json['total_likers'] as num).toInt(),
isLiked: json['is_liked'] as bool,
);
Map<String, dynamic> _$$DietLikesModelImplToJson(
_$DietLikesModelImpl instance) =>
<String, dynamic>{
'total_likers': instance.totalLikes,
'is_liked': instance.isLiked,
};

View File

@@ -0,0 +1,106 @@
import 'dart:async';
import 'package:eatvio_app/core/data/diet/models/diet_likes_model.dart';
import 'package:eatvio_app/core/data/diet/services/diet_service.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:equatable/equatable.dart';
class DietRepository {
DietRepository({required this.dietsService});
final DietService dietsService;
final _dietLikeStateStreamController = StreamController<DietLikesState>.broadcast();
final _dietFavoriteStateStreamController = StreamController<DietFavoriteState>.broadcast();
final _dietCommentsStateStreamController = StreamController<DietCommentsState>.broadcast();
Stream get dietLikeState => _dietLikeStateStreamController.stream;
Stream get dietFavoriteState => _dietFavoriteStateStreamController.stream;
Stream get dietCommentsState => _dietCommentsStateStreamController.stream;
Future<DietLikesModel> likeDiet(int id) async {
try {
return await dietsService.likeDiet(id: id);
} catch (e) {
rethrow;
}
}
Future<Diet> getDiet(int id) async {
try {
final diet = await dietsService.getDiet(id: id);
return diet;
} catch (e) {
rethrow;
}
}
Future<Diet> addToFavorite(int id) async {
try {
return await dietsService.addToFavorite(id: id);
} catch (e) {
rethrow;
}
}
Future<Diet> removeFromFavorite(int id) async {
try {
return await dietsService.removeFromFavorite(id: id);
} catch (e) {
rethrow;
}
}
void emitLikesStateToFeed(DietLikesState state) => _dietLikeStateStreamController.add(state);
void emitFavoriteStateToFeed(DietFavoriteState state) => _dietFavoriteStateStreamController.add(state);
void emitCommentsStateToFeed(DietCommentsState state) => _dietCommentsStateStreamController.add(state);
}
class DietLikesState extends Equatable {
final bool wasLikedByMe;
final int totalLikes;
final int index;
DietLikesState({
required this.wasLikedByMe,
required this.totalLikes,
required this.index,
});
@override
List<Object?> get props => [
wasLikedByMe,
totalLikes,
index,
];
}
class DietFavoriteState extends Equatable {
final bool isFavorite;
final int index;
DietFavoriteState({
required this.isFavorite,
required this.index,
});
@override
List<Object?> get props => [
isFavorite,
index,
];
}
class DietCommentsState extends Equatable {
final int index;
final int totalComments;
DietCommentsState({
required this.index,
required this.totalComments,
});
@override
List<Object?> get props => [
index,
totalComments,
];
}

View File

@@ -1,30 +1,26 @@
import 'package:dio/dio.dart';
import 'package:eatvio_app/core/data/diet/models/diet_likes_model.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:retrofit/retrofit.dart';
part 'diets_service.g.dart';
part 'diet_service.g.dart';
@RestApi()
abstract class DietsService {
factory DietsService(Dio dio, {String baseUrl}) = _DietsService;
abstract class DietService {
factory DietService(Dio dio, {String baseUrl}) = _DietService;
@POST('/api/diets/{id}/like')
Future<void> likeDiet({
Future<DietLikesModel> likeDiet({
@Path() required int id,
});
@POST('/api/diets/{id}/add_to_favorite')
Future<void> addToFavorite({
Future<Diet> addToFavorite({
@Path() required int id,
});
@POST('/api/diets/{id}/remove_from_favorite')
Future<void> removeFromFavorite({
@Path() required int id,
});
@POST('/api/diets/{id}/unliked')
Future<void> unlikeDiet({
Future<Diet> removeFromFavorite({
@Path() required int id,
});
@@ -32,5 +28,4 @@ abstract class DietsService {
Future<Diet> getDiet({
@Path() required int id,
});
}

View File

@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'diets_service.dart';
part of 'diet_service.dart';
// **************************************************************************
// RetrofitGenerator
@@ -8,8 +8,8 @@ part of 'diets_service.dart';
// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations
class _DietsService implements DietsService {
_DietsService(
class _DietService implements DietService {
_DietService(
this._dio, {
this.baseUrl,
this.errorLogger,
@@ -22,12 +22,12 @@ class _DietsService implements DietsService {
final ParseErrorLogger? errorLogger;
@override
Future<void> likeDiet({required int id}) async {
Future<DietLikesModel> likeDiet({required int id}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(Options(
final _options = _setStreamType<DietLikesModel>(Options(
method: 'POST',
headers: _headers,
extra: _extra,
@@ -43,16 +43,24 @@ class _DietsService implements DietsService {
_dio.options.baseUrl,
baseUrl,
)));
await _dio.fetch<void>(_options);
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
late DietLikesModel _value;
try {
_value = DietLikesModel.fromJson(_result.data!);
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
rethrow;
}
return _value;
}
@override
Future<void> addToFavorite({required int id}) async {
Future<Diet> addToFavorite({required int id}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(Options(
final _options = _setStreamType<Diet>(Options(
method: 'POST',
headers: _headers,
extra: _extra,
@@ -68,16 +76,24 @@ class _DietsService implements DietsService {
_dio.options.baseUrl,
baseUrl,
)));
await _dio.fetch<void>(_options);
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
late Diet _value;
try {
_value = Diet.fromJson(_result.data!);
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
rethrow;
}
return _value;
}
@override
Future<void> removeFromFavorite({required int id}) async {
Future<Diet> removeFromFavorite({required int id}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(Options(
final _options = _setStreamType<Diet>(Options(
method: 'POST',
headers: _headers,
extra: _extra,
@@ -93,32 +109,15 @@ class _DietsService implements DietsService {
_dio.options.baseUrl,
baseUrl,
)));
await _dio.fetch<void>(_options);
}
@override
Future<void> unlikeDiet({required int id}) async {
final _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
const Map<String, dynamic>? _data = null;
final _options = _setStreamType<void>(Options(
method: 'POST',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/api/diets/${id}/unliked',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(
_dio.options.baseUrl,
baseUrl,
)));
await _dio.fetch<void>(_options);
final _result = await _dio.fetch<Map<String, dynamic>>(_options);
late Diet _value;
try {
_value = Diet.fromJson(_result.data!);
} on Object catch (e, s) {
errorLogger?.logError(e, s, _options);
rethrow;
}
return _value;
}
@override

View File

@@ -0,0 +1,44 @@
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
class BookmarkButton extends StatelessWidget {
const BookmarkButton({
super.key,
required this.onTap,
required this.color,
required this.isFavorite,
required this.width,
required this.height,
required this.size,
this.shape,
this.borderRadius,
});
final void Function() onTap;
final Color color;
final BoxShape? shape;
final bool isFavorite;
final BorderRadiusGeometry? borderRadius;
final double width;
final double height;
final double size;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
width: width,
height: height,
decoration: BoxDecoration(
color: color,
shape: shape ?? BoxShape.rectangle,
borderRadius: borderRadius,
),
child: Icon(
isFavorite ? Icons.bookmark : Icons.bookmark_border_rounded,
color: appTheme.black,
size: size,
),
),
);
}
}

View File

@@ -0,0 +1,15 @@
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
class BottomSheetHandlerBar extends StatelessWidget {
const BottomSheetHandlerBar({super.key});
@override
Widget build(BuildContext context) {
return Container(
height: 4,
width: 40,
decoration: BoxDecoration(color: appTheme.lightGray, borderRadius: BorderRadius.circular(20)),
);
}
}

View File

@@ -0,0 +1,66 @@
import 'package:eatvio_app/core/utils/localization_utils.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/type_badges.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/custom_text_style.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class DietInfoRow extends StatelessWidget {
const DietInfoRow({super.key, required this.diet, this.itemsBackgroundColor, this.disableDescriptionOfTypes = false});
final Color? itemsBackgroundColor;
final Diet diet;
final bool disableDescriptionOfTypes;
@override
Widget build(BuildContext context) {
final s = S.of(context);
return SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16),
scrollDirection: Axis.horizontal,
child: Row(
children: [
InfoBouble(
backgroundColor: itemsBackgroundColor,
children: [
SvgPicture.asset(
'assets/icons/time2.svg',
width: 13.3,
height: 13.3,
),
SizedBox(width: 4),
Text(
diet.duration.toString() + ' ' + getDayForm(diet.duration, s),
style: TextStyles.textXSSemibold.copyWith(color: appTheme.black),
),
],
),
SizedBox(width: 12),
InfoBouble(
backgroundColor: itemsBackgroundColor,
children: [
SvgPicture.asset(
'assets/icons/people.svg',
width: 13.3,
height: 13.3,
),
SizedBox(width: 4),
Text(
'80 человек прошли',
style: TextStyles.textXSSemibold.copyWith(color: appTheme.black),
),
],
),
SizedBox(width: 12),
InfoBouble(
backgroundColor: itemsBackgroundColor,
children: [
TypeBadges(type: diet.type, disableDescriptionOfTypes: disableDescriptionOfTypes),
],
),
],
),
);
}
}

View File

@@ -0,0 +1,51 @@
import 'package:eatvio_app/theme/custom_text_style.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class FeedIconButton extends StatelessWidget {
const FeedIconButton({super.key, this.icon, this.svgIcon, this.text, this.onTap, this.iconColor, this.backgroundColor, this.textColor});
final IconData? icon;
final SvgPicture? svgIcon;
final String? text;
final Function()? onTap;
final Color? iconColor;
final Color? backgroundColor;
final Color? textColor;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap ?? () {},
borderRadius: BorderRadius.circular(16),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: backgroundColor ?? appTheme.gray100,
borderRadius: BorderRadius.circular(16),
),
height: 32,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (svgIcon != null) svgIcon!,
if (icon != null)
Icon(
icon,
size: 16,
color: iconColor ?? appTheme.gray600,
),
if (text != null) ...[
SizedBox(width: 8),
Text(
text!,
style: TextStyles.textSMedium.copyWith(
color: textColor ?? appTheme.gray600,
),
),
],
],
),
),
);
}
}

View File

@@ -119,7 +119,7 @@ class _ChatScreenState extends State<ChatScreen> {
Text(
state.chatRoom.users['to_chat_user']!.name,
style: CustomTextStyles.titleSmallBold.copyWith(
color: PrimaryColors().blueGray800,
color: PrimaryColors().black,
),
),
AnimatedCrossFade(

View File

@@ -2,24 +2,27 @@ import 'dart:async';
import 'dart:developer';
import 'package:easy_debounce/easy_debounce.dart';
import 'package:eatvio_app/core/data/diet/repositories/diet_repository.dart';
import 'package:eatvio_app/features/diets/presentation/bloc/about_diet_state.dart';
import 'package:eatvio_app/features/diets/repositories/diets_repository.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class AboutDietCubit extends Cubit<AboutDietState> {
AboutDietCubit({required this.dietsRepository}) : super(AboutDietState.initial());
final DietsRepository dietsRepository;
final DietRepository dietsRepository;
Future<void> getDiet(int id) async {
Future<void> getDiet(int id, {int? index}) async {
try {
final diet = await dietsRepository.getDiet(id);
if (index != null) {
dietsRepository.emitCommentsStateToFeed(DietCommentsState(index: index, totalComments: diet.totalComments));
}
emit(AboutDietState.loaded(diet));
} catch (e) {
log(e.toString());
}
}
Future<void> getDietWithLoading(int id) async{
Future<void> getDietWithLoading(int id) async {
try {
emit(AboutDietState.loading());
final diet = await dietsRepository.getDiet(id);
@@ -29,7 +32,7 @@ class AboutDietCubit extends Cubit<AboutDietState> {
}
}
Future<void> likeDiet(int id) async {
Future<void> likeDiet(int id, int dietIndexInFeed) async {
if (state is! DietStateLoaded) return;
final currentDiet = (state as DietStateLoaded).diet;
@@ -39,12 +42,15 @@ class AboutDietCubit extends Cubit<AboutDietState> {
totalLikes: currentDiet.totalLikes - 1,
wasLikedByMe: false,
);
dietsRepository.emitLikesStateToFeed(DietLikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed));
emit(AboutDietState.loaded(updatedDiet));
} else {
final updatedDiet = currentDiet.copyWith(
totalLikes: currentDiet.totalLikes + 1,
wasLikedByMe: true,
);
dietsRepository.emitLikesStateToFeed(DietLikesState(wasLikedByMe: updatedDiet.wasLikedByMe, totalLikes: updatedDiet.totalLikes, index: dietIndexInFeed));
emit(AboutDietState.loaded(updatedDiet));
}
@@ -53,17 +59,24 @@ class AboutDietCubit extends Cubit<AboutDietState> {
Duration(seconds: 1),
() async {
try {
await dietsRepository.likeDiet(id);
await getDiet(id);
final dietLikeStateData = await dietsRepository.likeDiet(id);
final actualDiet = currentDiet.copyWith(
wasLikedByMe: dietLikeStateData.isLiked,
totalLikes: dietLikeStateData.totalLikes,
);
emit(AboutDietState.loaded(actualDiet));
dietsRepository.emitLikesStateToFeed(DietLikesState(wasLikedByMe: actualDiet.wasLikedByMe, totalLikes: actualDiet.totalLikes, index: dietIndexInFeed));
} catch (e) {
log(e.toString());
dietsRepository
.emitLikesStateToFeed(DietLikesState(wasLikedByMe: currentDiet.wasLikedByMe, totalLikes: currentDiet.totalLikes, index: dietIndexInFeed));
emit(AboutDietState.loaded(currentDiet));
}
},
);
}
Future<void> addToFavorite(int id) async {
Future<void> addToFavorite(int id, int dietIndexInFeed) async {
if (state is! DietStateLoaded) return;
final currentDiet = (state as DietStateLoaded).diet;
@@ -71,6 +84,7 @@ class AboutDietCubit extends Cubit<AboutDietState> {
final updatedDiet = currentDiet.copyWith(
isFavorite: true,
);
dietsRepository.emitFavoriteStateToFeed(DietFavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndexInFeed));
emit(AboutDietState.loaded(updatedDiet));
EasyDebounce.debounce(
@@ -78,17 +92,19 @@ class AboutDietCubit extends Cubit<AboutDietState> {
Duration(seconds: 1),
() async {
try {
await dietsRepository.addToFavorite(id);
await getDiet(id);
final diet = await dietsRepository.addToFavorite(id);
emit(AboutDietState.loaded(diet));
dietsRepository.emitFavoriteStateToFeed(DietFavoriteState(isFavorite: diet.isFavorite, index: dietIndexInFeed));
} catch (e) {
log(e.toString());
dietsRepository.emitFavoriteStateToFeed(DietFavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndexInFeed));
emit(AboutDietState.loaded(currentDiet));
}
},
);
}
Future<void> removeFromFavorite(int id) async {
Future<void> removeFromFavorite(int id, int dietIndexInFeed) async {
if (state is! DietStateLoaded) return;
final currentDiet = (state as DietStateLoaded).diet;
@@ -96,6 +112,7 @@ class AboutDietCubit extends Cubit<AboutDietState> {
final updatedDiet = currentDiet.copyWith(
isFavorite: false,
);
dietsRepository.emitFavoriteStateToFeed(DietFavoriteState(isFavorite: updatedDiet.isFavorite, index: dietIndexInFeed));
emit(AboutDietState.loaded(updatedDiet));
EasyDebounce.debounce(
@@ -103,10 +120,12 @@ class AboutDietCubit extends Cubit<AboutDietState> {
Duration(seconds: 1),
() async {
try {
await dietsRepository.removeFromFavorite(id);
await getDiet(id);
final diet = await dietsRepository.removeFromFavorite(id);
emit(AboutDietState.loaded(diet));
dietsRepository.emitFavoriteStateToFeed(DietFavoriteState(isFavorite: diet.isFavorite, index: dietIndexInFeed));
} catch (e) {
log(e.toString());
dietsRepository.emitFavoriteStateToFeed(DietFavoriteState(isFavorite: currentDiet.isFavorite, index: dietIndexInFeed));
emit(AboutDietState.loaded(currentDiet));
}
},

View File

@@ -4,7 +4,9 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/utils/localization_utils.dart';
import 'package:eatvio_app/core/utils/string_extentions.dart';
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
import 'package:eatvio_app/core/widgets/custom_divider.dart';
import 'package:eatvio_app/core/widgets/diet_info_row.dart';
import 'package:eatvio_app/features/diets/presentation/bloc/about_diet_cubit.dart';
import 'package:eatvio_app/features/diets/presentation/bloc/about_diet_state.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/author_card.dart';
@@ -14,13 +16,13 @@ import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart'
import 'package:eatvio_app/features/diets/presentation/widgets/main_background_bouble.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/start_diet_bottom_sheet.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/type_badges.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_state.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/comments_widget.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/locator_service.dart';
import 'package:eatvio_app/theme/custom_text_style.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -30,9 +32,11 @@ import 'package:rive/rive.dart' hide LinearGradient;
class AboutDietScreen extends StatefulWidget {
final Diet diet;
final int index;
final bool navigateToComments;
late final List<int> selectedIndexes;
AboutDietScreen({super.key, required this.diet}) {
AboutDietScreen({super.key, required this.diet, required this.index, required this.navigateToComments}) {
selectedIndexes = List.generate(diet.dailySchedule.length, (_) => 0);
}
@@ -47,7 +51,7 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
final ScrollController scrollController = ScrollController();
final textEditingController = TextEditingController();
bool isMoreOptionsVisible = false;
bool _jumped = false;
@override
void initState() {
super.initState();
@@ -60,6 +64,13 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
});
}
void _scrollToBottom() {
_jumped = true;
scrollController.jumpTo(
scrollController.position.maxScrollExtent,
);
}
@override
Widget build(BuildContext context) {
final s = S.of(context);
@@ -83,440 +94,389 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
builder: (BuildContext context, CommentsState state) {
return BlocBuilder<AboutDietCubit, AboutDietState>(
builder: (context, dietState) {
return dietState is DietStateLoaded
? Scaffold(
backgroundColor: appTheme.gray100,
resizeToAvoidBottomInset: true,
bottomSheet: Container(
padding: EdgeInsets.symmetric(vertical: 12) + (Platform.isIOS ? const EdgeInsets.only(bottom: 16) : EdgeInsets.zero),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(
color: Colors.black.withOpacity(0.1),
),
),
if (dietState is DietStateLoaded) {
Future.delayed(Duration(milliseconds: 500), () {
if (widget.navigateToComments && !_jumped) {
_scrollToBottom();
}
});
return Scaffold(
backgroundColor: appTheme.gray100,
resizeToAvoidBottomInset: true,
bottomSheet: Container(
padding: EdgeInsets.symmetric(vertical: 12) + (Platform.isIOS ? const EdgeInsets.only(bottom: 16) : EdgeInsets.zero),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(
color: Colors.black.withOpacity(0.1),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Row(
children: [
Expanded(
child: SizedBox(
child: FloatingActionButton.extended(
heroTag: 'nextButtonRegistration',
highlightElevation: 0,
elevation: 0,
focusElevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
backgroundColor: appTheme.greenA700,
onPressed: () {
showModalBottomSheet(context: context, builder: (context) => StartDietBottomSheet());
},
label: Text(
s.startDiet,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: appTheme.whiteA700,
),
),
),
Expanded(
child: SizedBox(
child: FloatingActionButton.extended(
heroTag: 'nextButtonRegistration',
highlightElevation: 0,
elevation: 0,
focusElevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
SizedBox(width: 8),
GestureDetector(
onTap: () {
if (dietState.diet.isFavorite) {
dietsCubit.removeFromFavorite(widget.diet.id);
} else {
dietsCubit.addToFavorite(widget.diet.id);
}
backgroundColor: appTheme.greenA700,
onPressed: () {
showModalBottomSheet(context: context, builder: (context) => StartDietBottomSheet());
},
child: Container(
width: 52,
height: 52,
decoration: BoxDecoration(color: appTheme.gray50, shape: BoxShape.circle),
child: Icon(
dietState.diet.isFavorite ? Icons.bookmark : Icons.bookmark_border_rounded,
color: appTheme.blueGray800,
size: 24,
),
label: Text(
s.startDiet,
style: TextStyles.textMSemibold.copyWith(color: appTheme.whiteA700),
),
),
],
),
),
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (replyId != null)
GestureDetector(
onTap: () {
context.read<CommentsCubit>().setReplyId(null);
setState(() {
replyId = null;
textEditingController.clear();
});
FocusManager.instance.primaryFocus?.unfocus();
},
child: Container(
decoration: BoxDecoration(
color: appTheme.blueA400,
shape: BoxShape.circle,
),
height: 32,
width: 32,
child: Icon(
Icons.close_rounded,
size: 18,
color: Colors.white,
),
),
),
if (replyId != null) SizedBox(width: 8),
Expanded(
child: SizedBox(
child: TextFormField(
onChanged: (_) {
setState(() {});
},
controller: textEditingController,
maxLines: 5,
minLines: 1,
keyboardType: TextInputType.multiline,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Colors.black,
height: 1,
),
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
hintText: s.comment.capitalize(),
hintStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
height: 1,
color: Color(0xFFAEAEB2),
),
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide(
color: Color(0xFFD1D1D6),
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide(
color: Color(0xFFD1D1D6),
width: 1,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide(
color: Color(0xFFD1D1D6),
width: 1,
),
),
),
),
),
),
SizedBox(width: 8),
GestureDetector(
onTap: () {
if (textEditingController.text.length > 2) {
commentsCubit.sendComment(
id: widget.diet.id.toString(),
commentText: textEditingController.text,
parentCommentId: replyId,
commentSourceType: CommentSourceType.diet,
);
context.read<CommentsCubit>().setReplyId(null);
setState(() {
textEditingController.clear();
replyId = null;
});
dietsCubit.getDiet(widget.diet.id);
FocusManager.instance.primaryFocus?.unfocus();
}
},
child: Container(
decoration: BoxDecoration(
color: textEditingController.text.length > 2 ? appTheme.blueA400 : appTheme.gray50,
shape: BoxShape.circle,
),
height: 32,
width: 32,
child: Icon(
Icons.send_rounded,
size: 18,
color: textEditingController.text.length > 2 ? appTheme.whiteA700 : appTheme.blueGray800,
),
),
),
],
SizedBox(width: 8),
BookmarkButton(
isFavorite: dietState.diet.isFavorite,
onTap: () {
if (dietState.diet.isFavorite) {
dietsCubit.removeFromFavorite(widget.diet.id, widget.index);
} else {
dietsCubit.addToFavorite(widget.diet.id, widget.index);
}
},
width: 52,
height: 52,
size: 24,
shape: BoxShape.circle,
color: appTheme.gray50,
),
],
),
),
),
appBar: AppBar(
centerTitle: true,
title: Text(
widget.diet.name,
maxLines: 2,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
softWrap: true,
style: TextStyle(
color: Colors.black,
fontSize: 24,
fontWeight: FontWeight.w500,
height: 1,
),
),
actions: [
PortalTarget(
visible: isMoreOptionsVisible,
portalFollower: MoreOptions(id: widget.diet.id),
anchor: Aligned(
shiftToWithinBound: AxisFlag(x: true, y: true),
follower: Alignment.topRight,
target: Alignment.bottomRight,
),
child: IconButton(
onPressed: () {
setState(() {
isMoreOptionsVisible = !isMoreOptionsVisible;
});
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (replyId != null)
GestureDetector(
onTap: () {
context.read<CommentsCubit>().setReplyId(null);
setState(() {
replyId = null;
textEditingController.clear();
});
FocusManager.instance.primaryFocus?.unfocus();
},
child: Container(
decoration: BoxDecoration(
color: appTheme.blueA400,
shape: BoxShape.circle,
),
height: 32,
width: 32,
child: Icon(
Icons.close_rounded,
size: 18,
color: Colors.white,
),
),
),
if (replyId != null) SizedBox(width: 8),
Expanded(
child: SizedBox(
child: TextFormField(
onChanged: (_) {
setState(() {});
},
controller: textEditingController,
maxLines: 5,
minLines: 1,
keyboardType: TextInputType.multiline,
style: TextStyles.textMMedium.copyWith(color: appTheme.black),
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
hintText: s.comment.capitalize(),
hintStyle: TextStyles.textMMedium.copyWith(color: appTheme.lightGray600),
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide(
color: Color(0xFFD1D1D6),
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide(
color: Color(0xFFD1D1D6),
width: 1,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide(
color: Color(0xFFD1D1D6),
width: 1,
),
),
),
),
),
),
SizedBox(width: 8),
GestureDetector(
onTap: () {
if (textEditingController.text.length > 2) {
commentsCubit.sendComment(
id: widget.diet.id.toString(),
commentText: textEditingController.text,
parentCommentId: replyId,
commentSourceType: CommentSourceType.diet,
);
context.read<CommentsCubit>().setReplyId(null);
setState(() {
textEditingController.clear();
replyId = null;
});
Future.delayed(Duration(milliseconds: 500), () {
dietsCubit.getDiet(widget.diet.id, index: widget.index);
});
FocusManager.instance.primaryFocus?.unfocus();
}
},
icon: SvgPicture.asset(
'assets/icons/more_button.svg',
width: 20,
height: 20,
),),
child: Container(
decoration: BoxDecoration(
color: textEditingController.text.length > 2 ? appTheme.blueA400 : appTheme.gray50,
shape: BoxShape.circle,
),
height: 32,
width: 32,
child: Icon(
Icons.send_rounded,
size: 18,
color: textEditingController.text.length > 2 ? appTheme.whiteA700 : appTheme.black,
),
),
),
],
),
],
),
body: SingleChildScrollView(
controller: scrollController,
padding: EdgeInsets.only(bottom: 160),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 8),
MainBackgroundBouble(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
),
),
appBar: AppBar(
centerTitle: true,
title: Text(
widget.diet.name,
maxLines: 2,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
softWrap: true,
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
),
actions: [
PortalTarget(
visible: isMoreOptionsVisible,
portalFollower: MoreOptions(id: widget.diet.id),
anchor: Aligned(
shiftToWithinBound: AxisFlag(x: true, y: true),
follower: Alignment.topRight,
target: Alignment.bottomRight,
),
child: IconButton(
onPressed: () {
setState(() {
isMoreOptionsVisible = !isMoreOptionsVisible;
});
},
icon: SvgPicture.asset(
'assets/icons/more_button.svg',
width: 20,
height: 20,
),
),
),
],
),
body: SingleChildScrollView(
controller: scrollController,
padding: EdgeInsets.only(bottom: 160),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 8),
MainBackgroundBouble(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
Stack(children: [
CachedNetworkImage(
imageUrl: baseUrl + '/storage/' + widget.diet.image,
),
Positioned(
bottom: 16,
left: 0,
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InfoBouble(
children: [
SvgPicture.asset('assets/icons/eye.svg', width: 18, height: 12),
SizedBox(width: 8),
Text(
dietState.diet.totalViews.toString(),
style: TextStyle(color: appTheme.blueGray800, fontSize: 12, fontWeight: FontWeight.w500),
),
],
backgroundColor: appTheme.whiteA700,
),
SizedBox(width: 12),
GestureDetector(
onTap: () {
dietsCubit.likeDiet(widget.diet.id);
},
child: InfoBouble(
children: [
SvgPicture.asset(
'assets/icons/heart.svg',
width: 14,
height: 12,
colorFilter: dietState.diet.wasLikedByMe ? ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn) : null,
),
SizedBox(width: 8),
Text(
dietState.diet.totalLikes.toString(),
style: TextStyle(color: appTheme.blueGray800, fontSize: 12, fontWeight: FontWeight.w500),
),
],
backgroundColor: appTheme.whiteA700,
),
),
SizedBox(width: 12),
InfoBouble(
children: [
SvgPicture.asset('assets/icons/comment2.svg', width: 13, height: 12),
SizedBox(width: 8),
Text(
dietState.diet.totalComments.toString(),
style: TextStyle(color: appTheme.blueGray800, fontSize: 12, fontWeight: FontWeight.w500),
),
],
backgroundColor: appTheme.whiteA700,
),
],
),
),
],),
SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
s.about_diet,
style: TextStyle(color: appTheme.blueGray800, fontSize: 20, fontWeight: FontWeight.w600),
),
CachedNetworkImage(
imageUrl: baseUrl + '/storage/' + widget.diet.image,
),
SizedBox(height: 12),
SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16),
scrollDirection: Axis.horizontal,
Positioned(
bottom: 16,
left: 0,
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InfoBouble(
children: [
SvgPicture.asset(
'assets/icons/time2.svg',
width: 13.3,
height: 13.3,
SvgPicture.asset('assets/icons/eye.svg', width: 18, height: 12),
SizedBox(width: 8),
Text(
dietState.diet.totalViews.toString(),
style: TextStyles.textXSSemibold.copyWith(color: appTheme.black),
),
SizedBox(width: 4),
Text(widget.diet.duration.toString() + ' ' + getDayForm(widget.diet.duration, s),
style: TextStyle(color: appTheme.blueGray800, fontSize: 12, fontWeight: FontWeight.w500),),
],
backgroundColor: appTheme.whiteA700,
),
SizedBox(width: 12),
GestureDetector(
onTap: () {
dietsCubit.likeDiet(widget.diet.id, widget.index);
},
child: InfoBouble(
children: [
SvgPicture.asset(
'assets/icons/heart.svg',
width: 14,
height: 12,
colorFilter: dietState.diet.wasLikedByMe ? ColorFilter.mode(appTheme.blueA400, BlendMode.srcIn) : null,
),
SizedBox(width: 8),
Text(
dietState.diet.totalLikes.toString(),
style: TextStyles.textXSSemibold.copyWith(color: appTheme.black),
),
],
backgroundColor: appTheme.whiteA700,
),
),
SizedBox(width: 12),
InfoBouble(
children: [
SvgPicture.asset(
'assets/icons/people.svg',
width: 13.3,
height: 13.3,
SvgPicture.asset('assets/icons/comment2.svg', width: 13, height: 12),
SizedBox(width: 8),
Text(
dietState.diet.totalComments.toString(),
style: TextStyles.textXSSemibold.copyWith(color: appTheme.black),
),
SizedBox(width: 4),
Text('80 человек прошли(статика, ещё нет бека)',
style: TextStyle(color: appTheme.blueGray800, fontSize: 12, fontWeight: FontWeight.w500),),
],
),
SizedBox(width: 12),
InfoBouble(
children: [
TypeBadges(type: widget.diet.type),
],
backgroundColor: appTheme.whiteA700,
),
],
),
),
ExpandableText(
text: widget.diet.details,
),
SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: AuthorCard(
author: widget.diet.author,
),
),
SizedBox(height: 16),
],
),
),
SizedBox(height: 16),
MainBackgroundBouble(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Center(
SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
s.diet_plan + '(${widget.diet.duration.toString()} ' + getDayForm(widget.diet.duration, s) + ')',
style: TextStyle(
color: appTheme.blueGray800,
fontSize: 20,
fontWeight: FontWeight.w600,
s.about_diet,
style: TextStyles.headingXLSemibold.copyWith(color: appTheme.black),
),
),
SizedBox(height: 12),
DietInfoRow(diet: widget.diet),
ExpandableText(
text: widget.diet.details,
),
SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: AuthorCard(
author: widget.diet.author,
),
),
SizedBox(height: 16),
],
),
),
SizedBox(height: 16),
MainBackgroundBouble(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Center(
child: Text(
s.diet_plan + '(${widget.diet.duration.toString()} ' + getDayForm(widget.diet.duration, s) + ')',
style: TextStyles.headingXLSemibold.copyWith(
color: appTheme.black,
),
),
),
),
),
SizedBox(height: 8),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
return _dayOfPlan(widget.diet.dailySchedule[index], index, s);
},
itemCount: widget.diet.dailySchedule.length,
),
MainBackgroundBouble(
padding: EdgeInsets.symmetric(vertical: 16),
child: Column(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 16),
alignment: Alignment.centerLeft,
child: Text(
dietState.diet.totalComments.toString() + ' ' + getCommentForm(widget.diet.totalComments, s),
style: TextStyles.textMMedium.copyWith(
color: appTheme.gray500,
),
),
),
),),
SizedBox(height: 8),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
return _dayOfPlan(widget.diet.dailySchedule[index], index, s);
},
itemCount: widget.diet.dailySchedule.length,
),
MainBackgroundBouble(
padding: EdgeInsets.symmetric(vertical: 16),
child: Column(children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 16),
alignment: Alignment.centerLeft,
child: Text(
dietState.diet.totalComments.toString() + ' ' + getCommentForm(widget.diet.totalComments, s),
style: TextStyle(
fontSize: 12,
color: appTheme.gray500,
fontWeight: FontWeight.w400,
SizedBox(height: 16),
if (state is CommentsStateLoading)
Padding(
padding: const EdgeInsets.all(32),
child: SizedBox(
height: 32,
width: 32,
child: RiveAnimation.asset(
'assets/rive_animations/loading.riv',
),
),
),
SizedBox(height: 16),
if (state is CommentsStateLoading)
Padding(
padding: const EdgeInsets.all(32),
child: SizedBox(
height: 32,
width: 32,
child: RiveAnimation.asset(
'assets/rive_animations/loading.riv',
),
),
),
if (state is CommentsStateLoaded)
CommentsWidget(
id: widget.diet.id.toString(),
commentSourceType: CommentSourceType.diet,
comment: state.comment,
replyId: replyId,
),
],),
),
],
),
),
)
: Scaffold(
body: Center(
child: SizedBox(
height: 32,
width: 32,
child: RiveAnimation.asset(
'assets/rive_animations/loading.riv',
if (state is CommentsStateLoaded)
CommentsWidget(
id: widget.diet.id.toString(),
commentSourceType: CommentSourceType.diet,
comment: state.comment,
replyId: replyId,
),
],
),
),
),
);
],
),
),
);
}
return Scaffold(
body: Center(
child: SizedBox(
height: 32,
width: 32,
child: RiveAnimation.asset(
'assets/rive_animations/loading.riv',
),
),
),
);
},
);
},
@@ -537,10 +497,8 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
label: Text((index + 1).toString()),
labelStyle: TextStyle(
labelStyle: TextStyles.textXSSemibold.copyWith(
color: index == widget.selectedIndexes[dayNumber] ? Colors.white : appTheme.gray600,
fontWeight: FontWeight.w500,
fontSize: 12,
),
selected: widget.selectedIndexes[dayNumber] == index,
backgroundColor: appTheme.gray100,
@@ -567,10 +525,8 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
children: [
Text(
s.day + ' ' + (dayNumber + 1).toString(),
style: TextStyle(
color: appTheme.blueGray800,
fontSize: 20,
fontWeight: FontWeight.w600,
style: TextStyles.headingXLSemibold.copyWith(
color: appTheme.black,
),
),
Padding(
@@ -579,10 +535,8 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
),
Text(
s.meal,
style: TextStyle(
color: appTheme.blueGray800,
fontSize: 16,
fontWeight: FontWeight.w500,
style: TextStyles.textMMedium.copyWith(
color: appTheme.black,
),
),
Row(
@@ -618,21 +572,20 @@ class _AboutDietScreenState extends State<AboutDietScreen> {
padding: const EdgeInsets.only(bottom: 12),
child: Row(
children: [
Text(
daily.name,
style: TextStyle(
color: appTheme.blueGray800,
fontSize: 16,
fontWeight: FontWeight.w500,
SizedBox(
width: MediaQuery.sizeOf(context).width * 0.6,
child: Text(
daily.name,
style: TextStyles.textMMedium.copyWith(
color: appTheme.black,
),
),
),
Spacer(),
Text(
daily.quantity.toString() + ' ' + getLocalizedMeasurementUnits(s, daily.portion),
style: TextStyle(
color: appTheme.blueGray800,
fontSize: 16,
fontWeight: FontWeight.w600,
style: TextStyles.textMSemibold.copyWith(
color: appTheme.black,
),
),
],

View File

@@ -1,6 +1,7 @@
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/custom_text_style.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
@@ -36,18 +37,14 @@ class AuthorCard extends StatelessWidget {
),
subtitle: Text(
author.authorName,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: appTheme.blueGray800,
style: TextStyles.textLSemibold.copyWith(
color: appTheme.black,
),
),
title: Text(
s.diet_author,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Color(0xFF6D6F71),
style: TextStyles.textSSemibold.copyWith(
color: appTheme.gray,
),
),
),
@@ -55,23 +52,23 @@ class AuthorCard extends StatelessWidget {
children: [
Text(
'Конслуьтант',
style: TextStyle(
color: appTheme.blueGray800,
fontSize: 16,
fontWeight: FontWeight.w500,
style: TextStyles.textMMedium.copyWith(
color: appTheme.black,
),
),
SizedBox(width: 10),
InfoBouble(radius: 12, backgroundColor: appTheme.whiteA700, children: [
Text(
'128-й в рейтинге',
style: TextStyle(
color: appTheme.blueA400,
fontSize: 16,
fontWeight: FontWeight.w500,
InfoBouble(
radius: 12,
backgroundColor: appTheme.whiteA700,
children: [
Text(
'128-й в рейтинге',
style: TextStyles.textMMediumAuto.copyWith(
color: appTheme.blueA400,
),
),
),
],),
],
),
],
),
],

View File

@@ -1,5 +1,7 @@
import 'package:eatvio_app/core/utils/string_extentions.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:table_calendar/table_calendar.dart';
class CalendarWidget extends StatefulWidget {
@@ -10,7 +12,7 @@ class CalendarWidget extends StatefulWidget {
}
class _CalendarWidgetState extends State<CalendarWidget> {
CalendarFormat _calendarFormat = CalendarFormat.month;
CalendarFormat _calendarFormat = CalendarFormat.week;
DateTime _focusedDay = DateTime.now();
DateTime? _selectedDay = DateTime.now();
@override
@@ -26,16 +28,25 @@ class _CalendarWidgetState extends State<CalendarWidget> {
locale: 'ru_RU',
startingDayOfWeek: StartingDayOfWeek.monday,
focusedDay: _focusedDay,
rangeStartDay: _selectedDay,
rangeEndDay: _selectedDay?.add(const Duration(days: 6)),
calendarFormat: _calendarFormat,
calendarBuilders: CalendarBuilders(
headerTitleBuilder: (context, day) {
final dateFormatter = DateFormat('MMMM', 'ru_RU');
return Center(
child: Text(
'${dateFormatter.format(day).capitalize()}',
style: TextStyle(color: appTheme.black, fontSize: 16, fontWeight: FontWeight.w400),
),
);
},
),
headerStyle: HeaderStyle(
titleCentered: true,
formatButtonVisible: false,
leftChevronVisible: false,
rightChevronVisible: false,
),
rowHeight: 40,
rowHeight: 64,
selectedDayPredicate: (day) {
return isSameDay(_selectedDay, day);
},
@@ -58,27 +69,36 @@ class _CalendarWidgetState extends State<CalendarWidget> {
_focusedDay = focusedDay;
},
calendarStyle: CalendarStyle(
weekendTextStyle: TextStyle(
color: appTheme.gray,
),
defaultTextStyle: TextStyle(
color: appTheme.gray,
),
weekendDecoration: BoxDecoration(
color: Colors.white,
color: appTheme.dividerColor,
shape: BoxShape.circle,
),
defaultDecoration: BoxDecoration(
color: Colors.white,
color: appTheme.dividerColor,
shape: BoxShape.circle,
),
selectedTextStyle: TextStyle(
color: appTheme.whiteA700,
),
selectedDecoration: BoxDecoration(
color: appTheme.blueA400,
shape: BoxShape.circle,
),
todayTextStyle: TextStyle(
color: Colors.black,
color: appTheme.gray,
),
todayDecoration: BoxDecoration(
border: Border.all(
color: appTheme.blueA400,
width: 2,
),
color: Colors.white,
color: appTheme.dividerColor,
shape: BoxShape.circle,
),
),

View File

@@ -1,4 +1,5 @@
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/custom_text_style.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
@@ -15,32 +16,35 @@ class CpfcContainer extends StatelessWidget {
return Container(
color: appTheme.cardBackground,
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Column(
children: [
Text('$calories', style: TextStyle(color: appTheme.blueGray800, fontSize: 16, fontWeight: FontWeight.w600)),
Text(s.calories, style: TextStyle(color: appTheme.blueGray800, fontSize: 12, fontWeight: FontWeight.w500)),
],
),
Column(
children: [
Text('$protein', style: TextStyle(color: appTheme.blueGray800, fontSize: 16, fontWeight: FontWeight.w600)),
Text(s.proteins, style: TextStyle(color: appTheme.blueGray800, fontSize: 12, fontWeight: FontWeight.w500)),
],
),
Column(
children: [
Text('$fat', style: TextStyle(color: appTheme.blueGray800, fontSize: 16, fontWeight: FontWeight.w600)),
Text(s.fats, style: TextStyle(color: appTheme.blueGray800, fontSize: 12, fontWeight: FontWeight.w500)),
],
),
Column(
children: [
Text('$carbohydrates', style: TextStyle(color: appTheme.blueGray800, fontSize: 16, fontWeight: FontWeight.w600)),
Text(s.carbohydrates, style: TextStyle(color: appTheme.blueGray800, fontSize: 12, fontWeight: FontWeight.w500)),
],
),
],),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
Text('$calories', style: TextStyles.textMSemibold.copyWith(color: appTheme.black)),
Text(s.calories, style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)),
],
),
Column(
children: [
Text('$protein', style: TextStyles.textMSemibold.copyWith(color: appTheme.black)),
Text(s.proteins, style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)),
],
),
Column(
children: [
Text('$fat', style: TextStyles.textMSemibold.copyWith(color: appTheme.black)),
Text(s.fats, style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)),
],
),
Column(
children: [
Text('$carbohydrates', style: TextStyles.textMSemibold.copyWith(color: appTheme.black)),
Text(s.carbohydrates, style: TextStyles.textXSSemibold.copyWith(color: appTheme.black)),
],
),
],
),
);
}
}

View File

@@ -1,6 +1,7 @@
import 'dart:math' as math;
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/custom_text_style.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
@@ -74,7 +75,7 @@ class _ExpandableTextState extends State<ExpandableText> {
children: [
Text(
isExpanded ? s.hide : s.expand,
style: TextStyle(color: appTheme.blueA400, fontSize: 16, fontWeight: FontWeight.w500),
style: TextStyles.textMMedium.copyWith(color: appTheme.blueA400),
),
Transform.rotate(angle: isExpanded ? math.pi : 0, child: SvgPicture.asset('assets/icons/arrow_down.svg', width: 12, height: 12)),
],

View File

@@ -3,6 +3,7 @@ import 'package:eatvio_app/core/utils/toasts.dart';
import 'package:eatvio_app/core/widgets/custom_divider.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/main_background_bouble.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/custom_text_style.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -17,83 +18,80 @@ class MoreOptions extends StatelessWidget {
Widget build(BuildContext context) {
final s = S.of(context);
return MainBackgroundBouble(
enableShadow: true,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(text: baseUrl + '/ru/diet/' + id.toString()));
showInfoToast(s.link_was_copied);
},
child: Row(
children: [
Text(
s.copy_link,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: appTheme.blueGray800,
),
enableShadow: true,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(text: baseUrl + '/ru/diet/' + id.toString()));
showInfoToast(s.link_was_copied);
},
child: Row(
children: [
Text(
s.copy_link,
style: TextStyles.textMMedium.copyWith(
color: appTheme.black,
),
Spacer(),
SvgPicture.asset('assets/icons/copy2.svg', width: 16, height: 20),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: CustomDivider(),
),
GestureDetector(
onTap: () => Share.shareUri(
Uri.parse(
baseUrl + '/ru/diet/' + id.toString(),
),
Spacer(),
SvgPicture.asset('assets/icons/copy2.svg', width: 16, height: 20),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: CustomDivider(),
),
GestureDetector(
onTap: () => Share.shareUri(
Uri.parse(
baseUrl + '/ru/diet/' + id.toString(),
),
child: Row(
children: [
Text(
s.share,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: appTheme.blueGray800,
),
),
child: Row(
children: [
Text(
s.share,
style: TextStyles.textMMedium.copyWith(
color: appTheme.black,
),
Spacer(),
SvgPicture.asset('assets/icons/share2.svg', width: 16, height: 20),
],
),
),
Spacer(),
SvgPicture.asset('assets/icons/share2.svg', width: 16, height: 20),
],
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: CustomDivider(),
),
GestureDetector(
onTap: () {
context.push('complainingScreen');
},
child: Row(
children: [
Text(
s.complain,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: appTheme.blueGray800,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: CustomDivider(),
),
GestureDetector(
onTap: () {
context.push('complainingScreen');
},
child: Row(
children: [
Text(
s.complain,
style: TextStyles.textMMedium.copyWith(
color: appTheme.black,
),
Spacer(),
SvgPicture.asset('assets/icons/complain.svg', width: 16, height: 20),
],
),
),
Spacer(),
SvgPicture.asset('assets/icons/complain.svg', width: 16, height: 20),
],
),
],
),
),
],
),
width: 272,);
),
width: 272,
);
}
}

View File

@@ -1,5 +1,8 @@
import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart';
import 'package:eatvio_app/core/widgets/custom_divider.dart';
import 'package:eatvio_app/features/diets/presentation/widgets/calendar_widget.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/custom_text_style.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:eatvio_app/widgets/custom_outlined_button.dart';
import 'package:flutter/material.dart';
@@ -13,38 +16,41 @@ class StartDietBottomSheet extends StatelessWidget {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 5),
Container(
height: 4,
width: 40,
decoration: BoxDecoration(color: appTheme.lightGrey, borderRadius: BorderRadius.circular(20)),
SizedBox(height: 4),
BottomSheetHandlerBar(),
SizedBox(height: 12),
Text(
s.startDiet,
style: TextStyles.headingXLSemibold.copyWith(
color: appTheme.black,
),
),
SizedBox(height: 22),
Text(s.startDiet,
style: TextStyle(
color: appTheme.blueGray800,
fontSize: 20,
fontWeight: FontWeight.w600,
),),
SizedBox(height: 12),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Text(s.choose_start_diet_date,
textAlign: TextAlign.center,
style: TextStyle(
color: appTheme.blueGray800,
fontSize: 16,
fontWeight: FontWeight.w500,
),),
child: Text(
s.choose_start_diet_date,
textAlign: TextAlign.center,
style: TextStyles.textMMedium.copyWith(
color: appTheme.black,
),
),
),
SizedBox(height: 12),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: CustomDivider(),
),
CalendarWidget(),
Padding(
padding: EdgeInsets.only(left: 16, right: 16, top: 20, bottom: 25),
padding: EdgeInsets.only(left: 16, right: 16, top: 16, bottom: 28),
child: CustomOutlinedButton(
height: 52,
text: s.continue_,
height: 60,
text: s.startDiet,
buttonTextStyle: TextStyles.textLSemibold.copyWith(
color: appTheme.whiteA700,
),
buttonStyle: ButtonStyle(
textStyle: WidgetStatePropertyAll(TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600)),
backgroundColor: WidgetStatePropertyAll(appTheme.blueA400),
side: WidgetStatePropertyAll(BorderSide.none),
),

View File

@@ -1,16 +1,17 @@
import 'package:eatvio_app/features/diets/presentation/widgets/main_background_bouble.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/custom_text_style.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:flutter_svg/svg.dart';
class TypeBadges extends StatefulWidget {
const TypeBadges({super.key, required this.type});
const TypeBadges({super.key, required this.type, required this.disableDescriptionOfTypes});
final DietType type;
final bool disableDescriptionOfTypes;
@override
State<TypeBadges> createState() => _TypeBadgesState();
}
@@ -23,48 +24,56 @@ class _TypeBadgesState extends State<TypeBadges> {
final s = S.of(context);
final List<(String, Widget)> badgeSource = [];
if (widget.type.alko == true) {
badgeSource.add((
'assets/icons/cocktail.svg',
_InfoOverlayEntry(
onClose: closeOverlay,
assetPath: 'assets/icons/cocktail.svg',
title: s.alko_type,
description: s.alko_type_desc,
)
),);
badgeSource.add(
(
'assets/icons/cocktail.svg',
_InfoOverlayEntry(
onClose: closeOverlay,
assetPath: 'assets/icons/cocktail.svg',
title: s.alko_type,
description: s.alko_type_desc,
)
),
);
}
if (widget.type.veg == true) {
badgeSource.add((
'assets/icons/broccoli.svg',
_InfoOverlayEntry(
onClose: closeOverlay,
assetPath: 'assets/icons/broccoli.svg',
title: s.vegan_type,
description: s.vegan_type_desc,
)
),);
badgeSource.add(
(
'assets/icons/broccoli.svg',
_InfoOverlayEntry(
onClose: closeOverlay,
assetPath: 'assets/icons/broccoli.svg',
title: s.vegan_type,
description: s.vegan_type_desc,
)
),
);
}
if (widget.type.corb == true) {
badgeSource.add((
'assets/icons/bread.svg',
_InfoOverlayEntry(
onClose: closeOverlay,
assetPath: 'assets/icons/bread.svg',
title: s.corb_type,
description: s.corb_type_desc,
)
),);
badgeSource.add(
(
'assets/icons/bread.svg',
_InfoOverlayEntry(
onClose: closeOverlay,
assetPath: 'assets/icons/bread.svg',
title: s.corb_type,
description: s.corb_type_desc,
)
),
);
}
if (widget.type.meat == true) {
badgeSource.add((
'assets/icons/meat2.svg',
_InfoOverlayEntry(
onClose: closeOverlay,
assetPath: 'assets/icons/meat2.svg',
title: s.meat_type,
description: s.meat_type_desc,
)
),);
badgeSource.add(
(
'assets/icons/meat2.svg',
_InfoOverlayEntry(
onClose: closeOverlay,
assetPath: 'assets/icons/meat2.svg',
title: s.meat_type,
description: s.meat_type_desc,
)
),
);
}
return Row(
children: List.generate(
@@ -81,19 +90,21 @@ class _TypeBadgesState extends State<TypeBadges> {
),
portalFollower: badgeSource[index].$2,
child: GestureDetector(
onTap: () {
for (int stateIndex = 0; stateIndex < overlaysVisibilityState.length; stateIndex++) {
if (index != stateIndex) {
setState(() {
overlaysVisibilityState[stateIndex] = false;
});
} else {
setState(() {
overlaysVisibilityState[stateIndex] = true;
});
}
}
},
onTap: widget.disableDescriptionOfTypes
? null
: () {
for (int stateIndex = 0; stateIndex < overlaysVisibilityState.length; stateIndex++) {
if (index != stateIndex) {
setState(() {
overlaysVisibilityState[stateIndex] = false;
});
} else {
setState(() {
overlaysVisibilityState[stateIndex] = true;
});
}
}
},
child: Padding(
padding: EdgeInsets.only(right: index != badgeSource.length - 1 ? 8.0 : 0),
child: SvgPicture.asset(
@@ -152,22 +163,19 @@ class _InfoOverlayEntry extends StatelessWidget {
children: [
Text(
title,
style: TextStyle(
style: TextStyles.textMMedium.copyWith(
decoration: TextDecoration.none,
color: appTheme.blueGray800,
fontSize: 16,
fontWeight: FontWeight.w500,
color: appTheme.black,
),
),
SizedBox(height: 4),
Text(
description,
softWrap: true,
style: TextStyle(
style: TextStyles.textXSSemibold.copyWith(
decoration: TextDecoration.none,
color: appTheme.blueGray800,
fontSize: 12,
fontWeight: FontWeight.w500,
color: appTheme.black,
),
),
],

View File

@@ -1,48 +0,0 @@
import 'package:eatvio_app/features/diets/services/diets_service.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
class DietsRepository {
DietsRepository({required this.dietsService});
final DietsService dietsService;
Future<void> likeDiet(int id) async {
try {
await dietsService.likeDiet(id: id);
} catch (e) {
rethrow;
}
}
Future<void> unlikeDiet(int id) async {
try {
await dietsService.unlikeDiet(id: id);
} catch (e) {
rethrow;
}
}
Future<Diet> getDiet(int id) async {
try {
final diet = await dietsService.getDiet(id: id);
return diet;
} catch (e) {
rethrow;
}
}
Future<void> addToFavorite(int id) async {
try {
await dietsService.addToFavorite(id: id);
} catch (e) {
rethrow;
}
}
Future<void> removeFromFavorite(int id) async {
try {
await dietsService.removeFromFavorite(id: id);
} catch (e) {
rethrow;
}
}
}

View File

@@ -36,6 +36,7 @@ class Diet with _$Diet {
}) = _Diet;
factory Diet.fromJson(Map<String, dynamic> json) => _$DietFromJson(json);
}
@freezed

View File

@@ -1,15 +1,44 @@
import 'dart:async';
import 'dart:developer';
import 'package:easy_debounce/easy_debounce.dart';
import 'package:eatvio_app/core/data/diet/repositories/diet_repository.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_state.dart';
import 'package:eatvio_app/features/feed/repositories/feed_repository.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class DietsCubit extends Cubit<DietsState> {
final FeedRepository feedRepository;
final DietRepository dietsRepository;
int currentPage = 1;
late int lastPage;
bool isLoading = false;
String? _query;
late final StreamSubscription likesStateSubscription;
late final StreamSubscription favoriteStateSubscription;
late final StreamSubscription commentsStateSubscription;
DietsCubit({
required this.feedRepository,
required this.dietsRepository,
}) : super(const DietsState.loading()) {
likesStateSubscription = dietsRepository.dietLikeState.listen((likesState) {
_changeDietLikeState(likesState);
});
favoriteStateSubscription = dietsRepository.dietFavoriteState.listen((favoriteState) {
_changeDietFavoriteState(favoriteState);
});
commentsStateSubscription = dietsRepository.dietCommentsState.listen((commentsState) {
_changeDietCommentsState(commentsState);
});
}
DietsCubit({required this.feedRepository}) : super(const DietsState.loading());
@override
Future<void> close() async {
likesStateSubscription.cancel();
favoriteStateSubscription.cancel();
commentsStateSubscription.cancel();
super.close();
}
loadDiets({
String? query,
@@ -20,14 +49,18 @@ class DietsCubit extends Cubit<DietsState> {
query: query,
);
lastPage = dietsPagination.meta.lastPage;
emit(DietsState.loaded(
dietsList: dietsPagination.data,
isLoading: isLoading,
),);
emit(
DietsState.loaded(
dietsList: dietsPagination.data,
isLoading: isLoading,
),
);
} catch (e) {
emit(DietsState.error(
errorMessage: e.toString(),
),);
emit(
DietsState.error(
errorMessage: e.toString(),
),
);
}
}
@@ -60,4 +93,226 @@ class DietsCubit extends Cubit<DietsState> {
}
}
}
Future<void> likeDiet(int id, int index) async {
if (state is! DietsStateLoaded) return;
final currentDiets = (state as DietsStateLoaded).dietsList;
final dietsForModification = [...currentDiets];
final currentDiet = currentDiets[index];
if (currentDiet.wasLikedByMe) {
dietsForModification[index] = currentDiet.copyWith(
totalLikes: currentDiet.totalLikes - 1,
wasLikedByMe: false,
);
emit(
DietsState.loaded(
dietsList: [
...dietsForModification,
],
isLoading: isLoading,
),
);
} else {
dietsForModification[index] = currentDiet.copyWith(
totalLikes: currentDiet.totalLikes + 1,
wasLikedByMe: true,
);
emit(
DietsState.loaded(
dietsList: [
...dietsForModification,
],
isLoading: isLoading,
),
);
}
EasyDebounce.debounce(
'like_diet',
Duration(milliseconds: 200),
() async {
try {
final dietLikeStateData = await dietsRepository.likeDiet(id);
final actualDiet = currentDiet.copyWith(
wasLikedByMe: dietLikeStateData.isLiked,
totalLikes: dietLikeStateData.totalLikes,
);
dietsForModification[index] = actualDiet;
emit(
DietsState.loaded(
dietsList: [
...dietsForModification,
],
isLoading: isLoading,
),
);
} catch (e) {
log(e.toString());
emit(
DietsState.loaded(
dietsList: [
...currentDiets,
],
isLoading: isLoading,
),
);
}
},
);
}
void _changeDietLikeState(DietLikesState likesState) {
if (state is! DietsStateLoaded) return;
final currentDiets = (state as DietsStateLoaded).dietsList;
final dietsForModification = [...currentDiets];
final currentDiet = currentDiets[likesState.index];
dietsForModification[likesState.index] = currentDiet.copyWith(
totalLikes: likesState.totalLikes,
wasLikedByMe: likesState.wasLikedByMe,
);
emit(
DietsState.loaded(
dietsList: [
...dietsForModification,
],
isLoading: isLoading,
),
);
}
void _changeDietFavoriteState(DietFavoriteState favoriteState) {
if (state is! DietsStateLoaded) return;
final currentDiets = (state as DietsStateLoaded).dietsList;
final dietsForModification = [...currentDiets];
final currentDiet = currentDiets[favoriteState.index];
dietsForModification[favoriteState.index] = currentDiet.copyWith(
isFavorite: favoriteState.isFavorite,
);
emit(
DietsState.loaded(
dietsList: [
...dietsForModification,
],
isLoading: isLoading,
),
);
}
void _changeDietCommentsState(DietCommentsState commentsState) {
if (state is! DietsStateLoaded) return;
final currentDiets = (state as DietsStateLoaded).dietsList;
final dietsForModification = [...currentDiets];
final currentDiet = currentDiets[commentsState.index];
dietsForModification[commentsState.index] = currentDiet.copyWith(
totalComments: commentsState.totalComments,
);
emit(
DietsState.loaded(
dietsList: [
...dietsForModification,
],
isLoading: isLoading,
),
);
}
Future<void> addDietToFavorite(int id, int index) async {
if (state is! DietsStateLoaded) return;
final currentDiets = (state as DietsStateLoaded).dietsList;
final dietsForModification = [...currentDiets];
final currentDiet = currentDiets[index];
dietsForModification[index] = currentDiet.copyWith(
isFavorite: true,
);
emit(
DietsState.loaded(
dietsList: [
...dietsForModification,
],
isLoading: isLoading,
),
);
EasyDebounce.debounce(
'add_or_remove_diet_from_favorite',
Duration(milliseconds: 200),
() async {
try {
final diet = await dietsRepository.addToFavorite(id);
dietsForModification[index] = diet;
emit(
DietsState.loaded(
dietsList: [
...dietsForModification,
],
isLoading: isLoading,
),
);
} catch (e) {
log(e.toString());
emit(
DietsState.loaded(
dietsList: [
...currentDiets,
],
isLoading: isLoading,
),
);
}
},
);
}
Future<void> removeDietFromFavorite(int id, int index) async {
if (state is! DietsStateLoaded) return;
final currentDiets = (state as DietsStateLoaded).dietsList;
final dietsForModification = [...currentDiets];
final currentDiet = currentDiets[index];
dietsForModification[index] = currentDiet.copyWith(
isFavorite: false,
);
emit(
DietsState.loaded(
dietsList: [
...dietsForModification,
],
isLoading: isLoading,
),
);
EasyDebounce.debounce(
'add_or_remove_diet_from_favorite',
Duration(milliseconds: 200),
() async {
try {
final diet = await dietsRepository.removeFromFavorite(id);
dietsForModification[index] = diet;
emit(
DietsState.loaded(
dietsList: [
...dietsForModification,
],
isLoading: isLoading,
),
);
} catch (e) {
log(e.toString());
emit(
DietsState.loaded(
dietsList: [
...currentDiets,
],
isLoading: isLoading,
),
);
}
},
);
}
}

View File

@@ -6,7 +6,10 @@ import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_state.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/blog_post_widget.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/choice_chip_widget.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/diet_filter_bottom_sheet.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/diets_widget.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/filter_badge.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/plan_widget.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/recipes_widget.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/tags_modal_widget.dart';
@@ -282,17 +285,28 @@ class _FeedScreenState extends State<FeedScreen> {
child: BlocBuilder<DietsCubit, DietsState>(
builder: (BuildContext context, DietsState state) {
if (state is DietsStateLoaded) {
return ListView.separated(
padding: EdgeInsets.symmetric(vertical: 8),
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) {
return DietsWidget(diet: state.dietsList[index]);
},
separatorBuilder: (context, index) {
return SizedBox(height: 8);
},
itemCount: state.dietsList.length,
return Stack(
children: [
ListView.separated(
padding: EdgeInsets.symmetric(vertical: 8),
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) {
return DietsWidget(diet: state.dietsList[index], index: index);
},
separatorBuilder: (context, index) {
return SizedBox(height: 8);
},
itemCount: state.dietsList.length,
),
Positioned(
right: 0,
bottom: 74,
child: FilterBadge(
filterBottomSheet: DietFilterBottomSheet(),
),
),
],
);
} else if (state is DietsStateError) {
return Scaffold(
@@ -384,15 +398,70 @@ class _FeedScreenState extends State<FeedScreen> {
scrollDirection: Axis.horizontal,
child: Row(
children: [
_choiceChipWidget(0),
ChoiceChipWidget(
index: 0,
selectedChipIndex: _selectedChipIndex,
chipsLabelList: chipsLabelList,
onSelected: (bool selected) {
setState(() {
_selectedChipIndex = 0;
searchController.clear();
FocusScope.of(context).requestFocus(new FocusNode());
});
},
),
SizedBox(width: 8),
_choiceChipWidget(1),
ChoiceChipWidget(
index: 1,
selectedChipIndex: _selectedChipIndex,
chipsLabelList: chipsLabelList,
onSelected: (bool selected) {
setState(() {
_selectedChipIndex = 1;
searchController.clear();
FocusScope.of(context).requestFocus(new FocusNode());
});
},
),
SizedBox(width: 8),
_choiceChipWidget(2),
ChoiceChipWidget(
index: 2,
selectedChipIndex: _selectedChipIndex,
chipsLabelList: chipsLabelList,
onSelected: (bool selected) {
setState(() {
_selectedChipIndex = 2;
searchController.clear();
FocusScope.of(context).requestFocus(new FocusNode());
});
},
),
SizedBox(width: 8),
_choiceChipWidget(3),
ChoiceChipWidget(
index: 3,
selectedChipIndex: _selectedChipIndex,
chipsLabelList: chipsLabelList,
onSelected: (bool selected) {
setState(() {
_selectedChipIndex = 3;
searchController.clear();
FocusScope.of(context).requestFocus(new FocusNode());
});
},
),
SizedBox(width: 8),
_choiceChipWidget(4),
ChoiceChipWidget(
index: 4,
selectedChipIndex: _selectedChipIndex,
chipsLabelList: chipsLabelList,
onSelected: (bool selected) {
setState(() {
_selectedChipIndex = 4;
searchController.clear();
FocusScope.of(context).requestFocus(new FocusNode());
});
},
),
],
),
),
@@ -500,31 +569,4 @@ class _FeedScreenState extends State<FeedScreen> {
);
}
_choiceChipWidget(int index) {
return ChoiceChip(
selectedColor: appTheme.blueA400,
pressElevation: 0,
showCheckmark: false,
side: BorderSide.none,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
label: Text(chipsLabelList[index]),
labelStyle: TextStyle(
color: index == _selectedChipIndex ? Colors.white : appTheme.gray600,
fontWeight: FontWeight.w500,
fontSize: 12,
),
selected: _selectedChipIndex == index,
backgroundColor: appTheme.gray100,
onSelected: (bool selected) {
setState(() {
_selectedChipIndex = index;
searchController.clear();
FocusScope.of(context).requestFocus(new FocusNode());
});
},
);
}
}

View File

@@ -2,6 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:dismissible_page/dismissible_page.dart';
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/utils/date_time_utils.dart';
import 'package:eatvio_app/core/widgets/feed_icon_button.dart';
import 'package:eatvio_app/features/chat/presentation/pages/photo_view_screen.dart';
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
@@ -153,7 +154,7 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
children: [
_iconButton(
FeedIconButton(
icon: isLiked ? Icons.favorite_rounded : Icons.favorite_border_rounded,
text: totalLikes.toString(),
iconColor: isLiked ? Colors.red.withOpacity(0.8) : null,
@@ -171,7 +172,7 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
},
),
SizedBox(width: 8),
_iconButton(
FeedIconButton(
svgIcon: SvgPicture.asset(
'assets/icons/comment.svg',
height: 20,
@@ -188,7 +189,7 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
),
),
SizedBox(width: 8),
_iconButton(
FeedIconButton(
svgIcon: SvgPicture.asset(
height: 20,
width: 20,
@@ -225,40 +226,4 @@ class _BlogPostWidgetState extends State<BlogPostWidget> {
),
);
}
_iconButton({IconData? icon, SvgPicture? svgIcon, String? text, Function()? onTap, Color? iconColor, Color? backgroundColor, Color? textColor}) {
return InkWell(
onTap: onTap ?? () {},
borderRadius: BorderRadius.circular(16),
child: Ink(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: backgroundColor ?? appTheme.gray100,
borderRadius: BorderRadius.circular(16),
),
height: 32,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (svgIcon != null) svgIcon,
if (icon != null)
Icon(
icon,
size: 20,
color: iconColor ?? appTheme.gray600,
),
if (text != null) SizedBox(width: 8),
if (text != null)
Text(
text,
style: TextStyle(
color: textColor ?? appTheme.gray600,
fontWeight: FontWeight.w500,
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,32 @@
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
class ChoiceChipWidget extends StatelessWidget {
const ChoiceChipWidget({super.key, required this.chipsLabelList, required this.index, required this.selectedChipIndex, required this.onSelected});
final List<String> chipsLabelList;
final int index;
final int selectedChipIndex;
final void Function(bool) onSelected;
@override
Widget build(BuildContext context) {
return ChoiceChip(
selectedColor: appTheme.blueA400,
pressElevation: 0,
showCheckmark: false,
side: BorderSide.none,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
label: Text(chipsLabelList[index]),
labelStyle: TextStyle(
color: index == selectedChipIndex ? Colors.white : appTheme.gray600,
fontWeight: FontWeight.w500,
fontSize: 12,
),
selected: selectedChipIndex == index,
backgroundColor: appTheme.gray100,
onSelected: onSelected,
);
}
}

View File

@@ -71,7 +71,7 @@ class _CommentsWidgetState extends State<CommentsWidget> {
comment.authorName,
style: TextStyle(
height: 1,
color: appTheme.grey,
color: appTheme.gray,
fontSize: 12,
fontWeight: FontWeight.w500,
),
@@ -81,7 +81,7 @@ class _CommentsWidgetState extends State<CommentsWidget> {
comment.body,
style: TextStyle(
height: 1,
color: appTheme.blueGray800,
color: appTheme.black,
fontSize: 12,
fontWeight: FontWeight.w500,
),
@@ -93,7 +93,7 @@ class _CommentsWidgetState extends State<CommentsWidget> {
comment.createdAt.format('dd MMMM', 'ru'),
style: TextStyle(
height: 1,
color: appTheme.grey,
color: appTheme.gray,
fontSize: 12,
fontWeight: FontWeight.w500,
),
@@ -108,7 +108,7 @@ class _CommentsWidgetState extends State<CommentsWidget> {
s.answer,
style: TextStyle(
height: 1,
color: appTheme.grey,
color: appTheme.gray,
fontSize: 12,
fontWeight: FontWeight.w500,
),

View File

@@ -0,0 +1,97 @@
import 'package:eatvio_app/core/widgets/bottom_sheet_handler_bar.dart';
import 'package:eatvio_app/core/widgets/custom_divider.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/type_choice_filter_widget.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:eatvio_app/theme/custom_text_style.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
class DietFilterBottomSheet extends StatelessWidget {
const DietFilterBottomSheet({super.key});
@override
Widget build(BuildContext context) {
final s = S.of(context);
return SizedBox(
width: MediaQuery.sizeOf(context).width,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 12),
Center(child: BottomSheetHandlerBar()),
SizedBox(height: 16),
Text(
s.order,
style: TextStyles.textMSemibold.copyWith(color: appTheme.black),
),
SizedBox(height: 12),
DropdownButtonFormField(
borderRadius: BorderRadius.circular(20),
dropdownColor: appTheme.qwe,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: const BorderRadius.all(Radius.circular(20)),
borderSide: BorderSide.none,
),
fillColor: appTheme.qwe,
filled: true,
),
value: 'qwe',
items: [
DropdownMenuItem(
child: Text('qwe'),
value: 'qwe',
),
DropdownMenuItem(
child: Text('qwe2'),
value: 'qwe2',
),
DropdownMenuItem(
child: Text('qwe3'),
value: 'qwe3',
),
],
onChanged: (value) {},
),
SizedBox(
height: 16,
),
CustomDivider(),
SizedBox(
height: 16,
),
Text(
s.diet_time,
style: TextStyles.textMSemibold.copyWith(color: appTheme.black),
),
SizedBox(
height: 12,
),
TypeChoiceFilterWidget(),
SizedBox(
height: 16,
),
CustomDivider(),
SizedBox(
height: 16,
),
Text(
s.diet_type,
style: TextStyles.textMSemibold.copyWith(color: appTheme.black),
),
SizedBox(
height: 12,
),
TypeChoiceFilterWidget(),
SizedBox(
height: 24,
),
],
),
),
);
}
}

View File

@@ -1,15 +1,27 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/widgets/bookmark_button.dart';
import 'package:eatvio_app/core/widgets/diet_info_row.dart';
import 'package:eatvio_app/core/widgets/feed_icon_button.dart';
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
import 'package:eatvio_app/theme/custom_text_style.dart';
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart';
import 'package:share_plus/share_plus.dart';
class DietsWidget extends StatefulWidget {
final Diet diet;
const DietsWidget({super.key, required this.diet});
final int index;
const DietsWidget({
super.key,
required this.diet,
required this.index,
});
@override
State<DietsWidget> createState() => _DietsWidgetState();
@@ -18,21 +30,21 @@ class DietsWidget extends StatefulWidget {
class _DietsWidgetState extends State<DietsWidget> {
@override
Widget build(BuildContext context) {
return InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () => GoRouter.of(context).pushNamed('aboutDietScreen', extra: widget.diet),
child: Ink(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
ClipRRect(
return DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
InkWell(
onTap: () =>
GoRouter.of(context).pushNamed('aboutDietScreen', extra: {'diet': widget.diet, 'index': widget.index, 'navigateToComments': false}),
child: ClipRRect(
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
child: CachedNetworkImage(
imageUrl: baseUrl + '/storage/' + widget.diet.image,
@@ -40,148 +52,120 @@ class _DietsWidgetState extends State<DietsWidget> {
width: MediaQuery.of(context).size.width,
),
),
Positioned(
left: 8,
bottom: 8,
child: Wrap(
runSpacing: 8,
children: [
_iconButton(Icons.fastfood, '139.9 ккал'),
SizedBox(width: 8),
_iconButton(Icons.timer_rounded, widget.diet.state),
SizedBox(width: 8),
_iconButton(Icons.fast_forward_rounded, widget.diet.duration.toString()),
],
),
),
Positioned(
left: 8,
top: 8,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.8),
borderRadius: BorderRadius.circular(16),
),
child: Row(
children: [
Icon(
Icons.favorite_rounded,
size: 16,
color: Colors.black,
),
SizedBox(width: 4),
Text(
widget.diet.totalLikes.toString(),
style: TextStyle(
fontSize: 12,
color: Colors.black,
fontWeight: FontWeight.w400,
),
),
],
),
),
),
Positioned(
right: 8,
top: 8,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.8),
borderRadius: BorderRadius.circular(16),
),
child: Row(
children: [
Icon(
Icons.visibility_rounded,
size: 16,
color: Colors.black,
),
SizedBox(width: 4),
Text(
widget.diet.totalViews.toString(),
style: TextStyle(
fontSize: 12,
color: Colors.black,
fontWeight: FontWeight.w400,
),
),
],
),
),
),
],
),
SizedBox(height: 12),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text(
widget.diet.name,
style: TextStyle(
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
),
if (widget.diet.details.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Html(
data: widget.diet.details.length > 200 ? widget.diet.details.substring(0, 200) : widget.diet.details,
style: {
"*": Style(
color: Colors.black87,
),
Positioned(
right: 14,
child: BookmarkButton(
onTap: () async {
if (widget.diet.isFavorite) {
await context.read<DietsCubit>().removeDietFromFavorite(widget.diet.id, widget.index);
} else {
await context.read<DietsCubit>().addDietToFavorite(widget.diet.id, widget.index);
}
},
color: appTheme.whiteA700,
isFavorite: widget.diet.isFavorite,
borderRadius: BorderRadius.vertical(bottom: Radius.circular(12)),
width: 40,
height: 44,
size: 19,
),
),
if (widget.diet.details.length > 200)
Positioned(
bottom: 16,
child: SizedBox(
width: MediaQuery.sizeOf(context).width,
child: DietInfoRow(
diet: widget.diet,
itemsBackgroundColor: appTheme.whiteA700,
disableDescriptionOfTypes: true,
),
),
),
],
),
SizedBox(height: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
'Читать полностью...',
style: TextStyle(
height: 1,
color: appTheme.blueA400,
decoration: TextDecoration.underline,
),
widget.diet.name,
style: TextStyles.textMSemibold.copyWith(color: appTheme.black),
),
),
SizedBox(height: 12),
],
),
),
);
}
_iconButton(IconData icon, [String? text]) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.8),
borderRadius: BorderRadius.circular(16),
),
height: 32,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon,
size: 16,
color: Colors.black,
if (widget.diet.details.isNotEmpty) ...[
SizedBox(
height: 12,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Html(
data: widget.diet.details.length > 200 ? widget.diet.details.substring(0, 200) + '...' : widget.diet.details,
style: {
"*": Style(
margin: Margins.zero,
color: appTheme.black,
fontSize: FontSize(TextStyles.textSMedium.fontSize ?? 14),
fontWeight: TextStyles.textSMedium.fontWeight ?? FontWeight.w400,
),
},
),
),
],
],
),
if (text != null) SizedBox(width: 8),
if (text != null)
Text(
text,
style: TextStyle(
fontSize: 12,
color: Colors.black,
fontWeight: FontWeight.w500,
),
Padding(
padding: const EdgeInsets.only(left: 16, top: 12),
child: Row(
children: [
FeedIconButton(
icon: widget.diet.wasLikedByMe ? Icons.favorite_rounded : Icons.favorite_border_rounded,
text: widget.diet.totalLikes.toString(),
iconColor: widget.diet.wasLikedByMe ? appTheme.blueA400 : null,
backgroundColor: widget.diet.wasLikedByMe ? appTheme.transparentBlue : null,
onTap: () async {
await context.read<DietsCubit>().likeDiet(widget.diet.id, widget.index);
},
),
SizedBox(
width: 12,
),
FeedIconButton(
icon: Icons.chat_bubble_outline,
text: widget.diet.totalComments.toString(),
onTap: () =>
GoRouter.of(context).pushNamed('aboutDietScreen', extra: {'diet': widget.diet, 'index': widget.index, 'navigateToComments': true}),
),
SizedBox(
width: 12,
),
FeedIconButton(
svgIcon: SvgPicture.asset('assets/icons/repost.svg'),
onTap: () async {
final result = await Share.shareUri(
Uri.parse(
baseUrl + '/ru/diet/' + widget.diet.id.toString(),
),
);
switch (result.status) {
case ShareResultStatus.success:
case ShareResultStatus.dismissed:
case ShareResultStatus.unavailable:
}
},
),
Spacer(),
FeedIconButton(
svgIcon: SvgPicture.asset('assets/icons/eye2.svg'),
text: widget.diet.totalViews.toString(),
backgroundColor: Colors.transparent,
),
],
),
),
SizedBox(height: 12),
],
),
);

View File

@@ -0,0 +1,84 @@
import 'package:eatvio_app/core/utils/localization_utils.dart';
import 'package:eatvio_app/features/feed/presentation/widgets/choice_chip_widget.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/widgets.dart';
class DurationChoiceFilterWidget extends StatefulWidget {
const DurationChoiceFilterWidget({super.key});
@override
State<DurationChoiceFilterWidget> createState() => _DurationChoiceFilterWidgetState();
}
class _DurationChoiceFilterWidgetState extends State<DurationChoiceFilterWidget> {
final List<String> chipsLabelList = [];
int selectedChipIndex = 0;
@override
void didChangeDependencies() {
final s = S.of(context);
super.didChangeDependencies();
if (chipsLabelList.isEmpty) {
chipsLabelList.add(s.all);
chipsLabelList.add('7 ${getDayForm(7, s)}');
chipsLabelList.add('14 ${getDayForm(14, s)}');
chipsLabelList.add('21 ${getDayForm(21, s)}');
}
}
@override
Widget build(BuildContext context) {
return Wrap(
children: [
ChoiceChipWidget(
chipsLabelList: chipsLabelList,
index: 0,
selectedChipIndex: selectedChipIndex,
onSelected: (selectedValue) {
setState(() {
selectedChipIndex = 0;
});
},
),
SizedBox(
width: 8,
),
ChoiceChipWidget(
chipsLabelList: chipsLabelList,
index: 1,
selectedChipIndex: selectedChipIndex,
onSelected: (selectedValue) {
setState(() {
selectedChipIndex = 1;
});
},
),
SizedBox(
width: 8,
),
ChoiceChipWidget(
chipsLabelList: chipsLabelList,
index: 2,
selectedChipIndex: selectedChipIndex,
onSelected: (selectedValue) {
setState(() {
selectedChipIndex = 2;
});
},
),
SizedBox(
width: 8,
),
ChoiceChipWidget(
chipsLabelList: chipsLabelList,
index: 3,
selectedChipIndex: selectedChipIndex,
onSelected: (selectedValue) {
setState(() {
selectedChipIndex = 3;
});
},
),
],
);
}
}

View File

@@ -0,0 +1,34 @@
import 'package:eatvio_app/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class FilterBadge extends StatelessWidget {
const FilterBadge({super.key, required this.filterBottomSheet});
final Widget filterBottomSheet;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) => filterBottomSheet,
useRootNavigator: true,
barrierColor: Colors.transparent,
backgroundColor: appTheme.whiteA700,);
},
child: Container(
padding: EdgeInsets.only(left: 20, top: 12, bottom: 12, right: 24),
width: 70,
decoration: BoxDecoration(
color: appTheme.blueA400,
borderRadius: BorderRadius.horizontal(left: Radius.circular(100)),
),
child: SvgPicture.asset(
'assets/icons/filter2.svg',
width: 24,
height: 16,
),
),
);
}
}

View File

@@ -0,0 +1,97 @@
import 'package:eatvio_app/features/feed/presentation/widgets/choice_chip_widget.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/widgets.dart';
class TypeChoiceFilterWidget extends StatefulWidget {
const TypeChoiceFilterWidget({super.key});
@override
State<TypeChoiceFilterWidget> createState() => _TypeChoiceFilterWidgetState();
}
class _TypeChoiceFilterWidgetState extends State<TypeChoiceFilterWidget> {
final List<String> chipsLabelList = [];
int selectedChipIndex = 0;
@override
void didChangeDependencies() {
final s = S.of(context);
super.didChangeDependencies();
if (chipsLabelList.isEmpty) {
chipsLabelList.add(s.all);
chipsLabelList.add(s.vegan_type);
chipsLabelList.add(s.alko_type);
chipsLabelList.add(s.corb_type);
chipsLabelList.add(s.meat_type);
}
}
@override
Widget build(BuildContext context) {
return Wrap(
children: [
ChoiceChipWidget(
chipsLabelList: chipsLabelList,
index: 0,
selectedChipIndex: selectedChipIndex,
onSelected: (selectedValue) {
setState(() {
selectedChipIndex = 0;
});
},
),
SizedBox(
width: 8,
),
ChoiceChipWidget(
chipsLabelList: chipsLabelList,
index: 1,
selectedChipIndex: selectedChipIndex,
onSelected: (selectedValue) {
setState(() {
selectedChipIndex = 1;
});
},
),
SizedBox(
width: 8,
),
ChoiceChipWidget(
chipsLabelList: chipsLabelList,
index: 2,
selectedChipIndex: selectedChipIndex,
onSelected: (selectedValue) {
setState(() {
selectedChipIndex = 2;
});
},
),
SizedBox(
width: 8,
),
ChoiceChipWidget(
chipsLabelList: chipsLabelList,
index: 3,
selectedChipIndex: selectedChipIndex,
onSelected: (selectedValue) {
setState(() {
selectedChipIndex = 3;
});
},
),
SizedBox(
width: 8,
),
ChoiceChipWidget(
chipsLabelList: chipsLabelList,
index: 4,
selectedChipIndex: selectedChipIndex,
onSelected: (selectedValue) {
setState(() {
selectedChipIndex = 4;
});
},
),
],
);
}
}

View File

@@ -153,4 +153,5 @@ class FeedRepository {
rethrow;
}
}
}

View File

@@ -27,7 +27,7 @@ abstract class FeedService {
@GET('/api/diets/index')
Future<DietsPagination> getDiets({
@Query('page') required int page,
@Query('query_search') String? query,
@Query('query_search') String? query,
});
@GET('/api/blogPosts/{id}/comments/show')
@@ -74,5 +74,6 @@ abstract class FeedService {
@POST('/api/blogPosts/{id}/unliked')
Future<void> unlikedBlogPost({
@Path() required int id,
});
});
}

View File

@@ -33,6 +33,7 @@ class MessageLookup extends MessageLookupByLibrary {
"alko_type": MessageLookupByLibrary.simpleMessage("Алкоголь"),
"alko_type_desc": MessageLookupByLibrary.simpleMessage(
"С некоторыми видами диет можно употреблять алкоголь в умеренных количествах. Рекомендуется совмещать вместе с низкокалорийными закусками.",),
"all": MessageLookupByLibrary.simpleMessage("Все"),
"allergies_presence":
MessageLookupByLibrary.simpleMessage("Наличие аллергии"),
"another_form_of_comment":
@@ -78,6 +79,8 @@ class MessageLookup extends MessageLookupByLibrary {
"diary": MessageLookupByLibrary.simpleMessage("Дневник"),
"diet_author": MessageLookupByLibrary.simpleMessage("Автор диеты"),
"diet_plan": MessageLookupByLibrary.simpleMessage("План диеты"),
"diet_time": MessageLookupByLibrary.simpleMessage("Время прохождения"),
"diet_type": MessageLookupByLibrary.simpleMessage("Тип диеты"),
"do_you_have_hypertension_tendency":
MessageLookupByLibrary.simpleMessage("Есть ли у вас гипертония?"),
"do_you_have_hypotension_tendency":
@@ -152,6 +155,7 @@ class MessageLookup extends MessageLookupByLibrary {
"no": MessageLookupByLibrary.simpleMessage("Нет"),
"no_account":
MessageLookupByLibrary.simpleMessage("У меня нет аккаунта"),
"order": MessageLookupByLibrary.simpleMessage("Порядок"),
"password": MessageLookupByLibrary.simpleMessage("Пароль"),
"password_confirmation":
MessageLookupByLibrary.simpleMessage("Подтвердите пароль"),

View File

@@ -1369,6 +1369,46 @@ class S {
args: [],
);
}
/// `Порядок`
String get order {
return Intl.message(
'Порядок',
name: 'order',
desc: '',
args: [],
);
}
/// `Время прохождения`
String get diet_time {
return Intl.message(
'Время прохождения',
name: 'diet_time',
desc: '',
args: [],
);
}
/// `Все`
String get all {
return Intl.message(
'Все',
name: 'all',
desc: '',
args: [],
);
}
/// `Тип диеты`
String get diet_type {
return Intl.message(
'Тип диеты',
name: 'diet_type',
desc: '',
args: [],
);
}
}
class AppLocalizationDelegate extends LocalizationsDelegate<S> {

View File

@@ -130,5 +130,9 @@
"answer": "Ответить",
"link_was_copied": "Ссылка успешно скопирована",
"choose_start_diet_date": "Выберите дату старты диеты. Она отобразиться у Вас в дневнике",
"continue_": "Продолжить"
"continue_": "Продолжить",
"order": "Порядок",
"diet_time": "Время прохождения",
"all": "Все",
"diet_type": "Тип диеты"
}

View File

@@ -1,5 +1,7 @@
import 'package:dio/dio.dart';
import 'package:eatvio_app/core/const.dart';
import 'package:eatvio_app/core/data/diet/repositories/diet_repository.dart';
import 'package:eatvio_app/core/data/diet/services/diet_service.dart';
import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart';
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/new_messages_cubit/new_messages_cubit.dart';
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/notifications_cubit/notifications_cubit.dart';
@@ -18,8 +20,6 @@ import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/repositories/diary_repository.dart';
import 'package:eatvio_app/features/diary/services/diary_service.dart';
import 'package:eatvio_app/features/diets/presentation/bloc/about_diet_cubit.dart';
import 'package:eatvio_app/features/diets/repositories/diets_repository.dart';
import 'package:eatvio_app/features/diets/services/diets_service.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/comments_cubit/comments_cubit.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
@@ -62,7 +62,7 @@ Future<void> init() async {
sl.registerFactory<ProfileCubit>(() => ProfileCubit(profileRepository: sl(), chatRepository: sl()));
sl.registerFactory<ProfileAvatarCubit>(() => ProfileAvatarCubit(profileRepository: sl()));
sl.registerFactory<RecipeCreateCubit>(() => RecipeCreateCubit(recipeRepository: sl()));
sl.registerFactory<DietsCubit>(() => DietsCubit(feedRepository: sl()));
sl.registerFactory<DietsCubit>(() => DietsCubit(feedRepository: sl(), dietsRepository: sl()));
sl.registerFactory<CommentsCubit>(() => CommentsCubit(feedRepository: sl()));
sl.registerFactory<ChatSelectCubit>(() => ChatSelectCubit(chatRepository: sl()));
sl.registerFactory<PlansCubit>(() => PlansCubit(plansRepository: sl()));
@@ -83,7 +83,7 @@ Future<void> init() async {
sl.registerLazySingleton<ConsultantRepository>(() => ConsultantRepository(consultantService: sl()));
sl.registerLazySingleton<DiaryRepository>(() => DiaryRepository(diaryService: sl()));
sl.registerLazySingleton<GlossaryRepository>(() => GlossaryRepository(glossaryService: sl()));
sl.registerLazySingleton<DietsRepository>(() => DietsRepository(dietsService: sl()));
sl.registerLazySingleton<DietRepository>(() => DietRepository(dietsService: sl()));
// Services
sl.registerLazySingleton<ChatService>(() => ChatService(sl()));
@@ -97,9 +97,8 @@ Future<void> init() async {
sl.registerLazySingleton<ConsultantService>(() => ConsultantService(sl()));
sl.registerLazySingleton<DiaryService>(() => DiaryService(sl()));
sl.registerLazySingleton<GlossaryService>(() => GlossaryService(sl()));
sl.registerLazySingleton<DietsService>(() => DietsService(sl()));
sl.registerLazySingleton<DietService>(() => DietService(sl()));
// External
sl.registerLazySingleton(
() => Dio(

View File

@@ -54,7 +54,7 @@ class AppDecoration {
static BoxDecoration get outlineBlueGray => BoxDecoration(
border: Border.all(
color: appTheme.blueGray800,
color: appTheme.black,
width: 1,
strokeAlign: strokeAlignOutside,
),
@@ -90,7 +90,7 @@ class BorderRadiusStyle {
static BoxDecoration get outlineBlueGray => BoxDecoration(
border: Border.all(
color: appTheme.blueGray800,
color: appTheme.black,
width: 1,
strokeAlign: strokeAlignOutside,
),

View File

@@ -24,15 +24,15 @@ class CustomTextStyles {
);
static get bodyMediumBluegray800 => theme.textTheme.bodyMedium!.copyWith(
color: appTheme.blueGray800,
color: appTheme.black,
);
static get bodyMediumBluegray800_1 => theme.textTheme.bodyMedium!.copyWith(
color: appTheme.blueGray800,
color: appTheme.black,
);
static get bodyMediumBluegray800_2 => theme.textTheme.bodyMedium!.copyWith(
color: appTheme.blueGray800,
color: appTheme.black,
);
static get bodyMediumWhiteA700 => theme.textTheme.bodyMedium!.copyWith(
@@ -45,17 +45,17 @@ class CustomTextStyles {
);
static get bodySmallMulishBluegray800 => theme.textTheme.bodySmall!.mulish.copyWith(
color: appTheme.blueGray800,
color: appTheme.black,
fontSize: 12,
);
static get bodySmallMulishBluegray80012 => theme.textTheme.bodySmall!.mulish.copyWith(
color: appTheme.blueGray800,
color: appTheme.black,
fontSize: 12,
);
static get bodySmallMulishBluegray80012_1 => theme.textTheme.bodySmall!.mulish.copyWith(
color: appTheme.blueGray800,
color: appTheme.black,
fontSize: 12,
);
@@ -116,16 +116,16 @@ class CustomTextStyles {
);
static get titleSmallBluegray800 => theme.textTheme.titleSmall!.copyWith(
color: appTheme.blueGray800,
color: appTheme.black,
);
static get titleSmallBluegray800Bold => theme.textTheme.titleSmall!.copyWith(
color: appTheme.blueGray800,
color: appTheme.black,
fontWeight: FontWeight.w700,
);
static get titleSmallBluegray800ExtraBold => theme.textTheme.titleSmall!.copyWith(
color: appTheme.blueGray800,
color: appTheme.black,
fontWeight: FontWeight.w800,
);
@@ -165,8 +165,6 @@ class CustomTextStyles {
static get titleSmallSegoeUIOnPrimary => theme.textTheme.titleSmall!.segoeUI.copyWith(
color: theme.colorScheme.onPrimary,
);
}
extension on TextStyle {
@@ -179,4 +177,52 @@ extension on TextStyle {
}
}
abstract class TextStyles {
static const headingXLSemibold = TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
height: 1.255,
);
static const textLSemibold = TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
height: 1.255,
);
static const textMSemibold = TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
height: 1.255,
);
static const textMMedium = TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
height: 1,
);
static const textMMediumAuto = TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
height: 1.255,
);
static const textSSemibold = TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
height: 1.255,
);
static const textSMedium = TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
height: 1.255,
);
static const textXSSemibold = TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
height: 1.255,
);
}

View File

@@ -114,7 +114,7 @@ class PrimaryColors {
// BlueGray
Color get blueGray300 => Color(0XFF9AA5B1);
Color get blueGray800 => Color(0XFF323F4B);
Color get black => Color(0XFF323F4B);
Color get blueGray900 => Color(0XFF2A2F4C);
@@ -169,9 +169,15 @@ class PrimaryColors {
Color get dividerColor => Color(0xFFF1F2F6);
Color get grey => Color(0xFF6D6F71);
Color get gray => Color(0xFF6D6F71);
Color get lightGrey => Color(0xFFCECECE);
Color get lightGray600 => Color(0xFFB0B0B0);
Color get lightGray => Color(0xFFCECECE);
Color get transparentBlue => Color(0xFF2F80ED).withOpacity(0.1);
Color get qwe => Color(0xFFF6F6F6);
}
PrimaryColors get appTheme => ThemeHelper().themeColor();