Skip to content

Commit

Permalink
feature: implemented the presentation layer of the news feed feature …
Browse files Browse the repository at this point in the history
…and connected th UI with the providers
  • Loading branch information
BasakK6 committed Sep 29, 2023
1 parent dcfd861 commit 2ebcf8b
Show file tree
Hide file tree
Showing 29 changed files with 932 additions and 93 deletions.
Binary file added assets/placeholder.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions lib/core/presentation/resources/assets_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const String kBaseAssetsPath = "assets";
const String kPlaceHolderImagePath = "$kBaseAssetsPath/placeholder.jpg";
25 changes: 25 additions & 0 deletions lib/core/presentation/resources/color_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'dart:ui';

const String kDarkPurpleHexCode = "#121421";
const String kDarkPurpleLighterHexCode = "#262B3F";
const String kPurpleHexCode = "#8800FF";
const String kPinkAccent30OpacityHexCode = "#801C41";
const String kPinkAccentHexCode = "#FF0066";
const String kPurpleAccentHexCode = "#FF00FF";
const String kTurquoiseHexCode = "#00FFCB";
const String kOrangeHexCode = "#FF7700";
const String kGreyHexCode = "#CBCBCB";
const String lightGreyHexCode = "#54596C";

//usage: ColorExtension.fromHex(purpleHexCode);

extension ColorExtension on Color {
static Color fromHex(String hexCode) {
hexCode = hexCode.replaceAll("#", "");
if (hexCode.length == 6) {
hexCode = "ff$hexCode"; //8 character long -> ff = opacity %100
}

return Color(int.parse(hexCode, radix: 16));
}
}
4 changes: 4 additions & 0 deletions lib/core/presentation/resources/strings_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const String kNewsFeedString = "News Feed";
const String kServerFailureString = "Server Failure";
const String kConnectivityFailureString = "Connectivity Failure";
const String kUnknownString = "Unknown";
13 changes: 13 additions & 0 deletions lib/core/presentation/resources/values_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const double kLeftRightPaddingFactor = 0.06;
const double kNewsItemLayoutMarginFactor = 0.025;
const double kRadius = 20;
const double kPaddingSmall = 2;
const double kDefaultHeightFactor = 0.25;
const double kSliverAppBarHeightFactor = 0.35;
const double kSliverBackgroundHeightFactor = 0.40;
const double kFooterHeightFactor = 0.10;
const double kBackArrowSizeFactor = 0.08;
const double kNewsItemTopMarginFactor = 0.02;
const double kNewsItemBottomMarginFactor = 0.01;
const double kNewsItemWidthFactor = 0.85;
const double kNewsItemHeightFactor = kDefaultHeightFactor / 2;
24 changes: 24 additions & 0 deletions lib/core/presentation/widgets/app_icon.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:news_app/core/presentation/resources/color_manager.dart';
import 'package:news_app/core/presentation/widgets/project_text_widgets.dart';

class AppIcon extends StatelessWidget {
const AppIcon({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
Icon(
Icons.circle,
color: ColorExtension.fromHex(kPurpleHexCode),
),
PlayFairDisplayText(
text: "N",
fontSize: 10,
),
],
);
}
}
33 changes: 33 additions & 0 deletions lib/core/presentation/widgets/category_chip.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:news_app/core/presentation/resources/color_manager.dart';
import 'package:news_app/core/presentation/resources/values_manager.dart';
import 'package:news_app/core/presentation/widgets/project_text_widgets.dart';
import 'package:news_app/core/utilities/string_extension.dart';
import 'package:news_app/features/news_feed/presentation/providers/chosen_category_provider.dart';

class CategoryChip extends ConsumerWidget {
const CategoryChip({
super.key,
});

@override
Widget build(BuildContext context, WidgetRef ref) {
return DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(kRadius),
color: ColorExtension.fromHex(kPinkAccent30OpacityHexCode),
),
child: Center(
child: Padding(
padding: const EdgeInsets.all(kPaddingSmall),
child: RobotoBoldText(
text: ref.watch(chosenCategoryProvider).capitalize(),
fontSize: 12,
color: ColorExtension.fromHex(kPinkAccentHexCode),
),
),
),
);
}
}
35 changes: 35 additions & 0 deletions lib/core/presentation/widgets/gradient_shadow_container.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
import 'package:news_app/core/presentation/resources/values_manager.dart';

class GradientShadowContainer extends StatelessWidget {
const GradientShadowContainer({Key? key, this.height, required this.child})
: super(key: key);

final double? height;
final Widget child;

@override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.sizeOf(context).width,
height:
height ?? MediaQuery.sizeOf(context).height * kDefaultHeightFactor,
decoration: BoxDecoration(
gradient: buildGradient(),
),
child: child,
);
}

LinearGradient buildGradient() {
return const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [
0.1,
0.6,
],
colors: [Colors.transparent, Colors.black54],
);
}
}
39 changes: 39 additions & 0 deletions lib/core/presentation/widgets/news_item_layout.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:news_app/core/presentation/resources/color_manager.dart';
import 'package:news_app/core/presentation/resources/values_manager.dart';
import 'package:news_app/core/presentation/widgets/news_summary_big_widget.dart';
import 'package:news_app/features/news_feed/domain/entities/news_feed_entity.dart';

class NewsItemLayout extends StatelessWidget {
const NewsItemLayout({Key? key, required this.articlesEntity})
: super(key: key);

final ArticlesEntity articlesEntity;

@override
Widget build(BuildContext context) {
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(kRadius),
),
color: ColorExtension.fromHex(kDarkPurpleLighterHexCode),
margin: buildMargin(context),
child: SizedBox(
width: MediaQuery.sizeOf(context).width * kNewsItemWidthFactor,
height: MediaQuery.sizeOf(context).height * kNewsItemHeightFactor,
child: NewsSummaryBigWidget(
articlesEntity: articlesEntity,
),
),
);
}

EdgeInsets buildMargin(BuildContext context) {
return EdgeInsets.only(
top: MediaQuery.sizeOf(context).height * kNewsItemTopMarginFactor,
left: MediaQuery.sizeOf(context).width * kLeftRightPaddingFactor,
right: MediaQuery.sizeOf(context).width * kLeftRightPaddingFactor,
bottom: MediaQuery.sizeOf(context).height * kNewsItemBottomMarginFactor,
);
}
}
90 changes: 90 additions & 0 deletions lib/core/presentation/widgets/news_summary_big_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:news_app/core/presentation/resources/color_manager.dart';
import 'package:news_app/core/presentation/resources/values_manager.dart';
import 'package:news_app/core/presentation/widgets/news_summary_small_widget.dart';
import 'package:news_app/core/presentation/widgets/project_fade_in_image.dart';
import 'package:news_app/core/presentation/widgets/project_text_widgets.dart';
import 'package:news_app/core/utilities/string_extension.dart';
import 'package:news_app/features/news_feed/domain/entities/news_feed_entity.dart';
import 'package:news_app/features/news_feed/presentation/providers/chosen_category_provider.dart';

class NewsSummaryBigWidget extends StatelessWidget {
const NewsSummaryBigWidget({Key? key, required this.articlesEntity})
: super(key: key);

final ArticlesEntity articlesEntity;

@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: buildNewsImage(context),
),
Expanded(
flex: 2,
child: Column(
children: [
Expanded(
child: Align(
alignment: Alignment.centerLeft,
child: buildCategoryTitle(),
),
),
Expanded(
flex: 3,
child: buildSmallNewsSummary(),
),
],
),
),
buildEmptySpace(context),
],
);
}

Container buildNewsImage(BuildContext context) {
return Container(
margin: EdgeInsets.all(
MediaQuery.sizeOf(context).width * kNewsItemLayoutMarginFactor,
),
decoration: BoxDecoration(
color: ColorExtension.fromHex(lightGreyHexCode),
borderRadius: BorderRadius.circular(kRadius),
),
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(kRadius),
child: ProjectFadeInImage(
networkImageURL: articlesEntity.urlToImage,
),
),
),
);
}

Consumer buildCategoryTitle() {
return Consumer(builder: (context, ref, child) {
return RobotoBoldText(
text: ref.watch(chosenCategoryProvider).capitalize(),
fontSize: 12,
color: ColorExtension.fromHex(kTurquoiseHexCode),
);
});
}

NewsSummarySmallWidget buildSmallNewsSummary() {
return NewsSummarySmallWidget(
articlesEntity: articlesEntity,
isCategoryIncluded: false,
titleFontSize: 14,
);
}

SizedBox buildEmptySpace(BuildContext context) {
return SizedBox(
width: MediaQuery.sizeOf(context).width * kNewsItemLayoutMarginFactor * 2,
);
}
}
83 changes: 83 additions & 0 deletions lib/core/presentation/widgets/news_summary_small_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import 'package:flutter/material.dart';
import 'package:news_app/core/presentation/widgets/category_chip.dart';
import 'package:news_app/core/presentation/widgets/project_text_widgets.dart';
import 'package:news_app/core/presentation/widgets/publish_time_widget.dart';
import 'package:news_app/core/presentation/widgets/source_info_widget.dart';
import 'package:news_app/features/news_feed/domain/entities/news_feed_entity.dart';

class NewsSummarySmallWidget extends StatelessWidget {
const NewsSummarySmallWidget({
super.key,
required this.articlesEntity,
required this.isCategoryIncluded,
this.titleFontSize,
});

final ArticlesEntity articlesEntity;
final bool isCategoryIncluded;
final double? titleFontSize;

@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
flex: 2,
child: Align(
alignment: Alignment.centerLeft,
child: buildTitle(),
),
),
const Spacer(),
Expanded(child: buildSubtitle()),
const Spacer()
],
);
}

Wrap buildTitle() {
return Wrap(
children: [
PlayFairDisplayText(
fontSize: titleFontSize ?? 18,
text: articlesEntity.title ?? "",
maxLines: 2,
)
],
);
}

Widget buildSubtitle() {
return Wrap(
children: [
Row(
children: [
Expanded(
flex: 4,
child: SourceInfoWidget(
source: articlesEntity.source?.name,
),
),
const Spacer(),
Expanded(
flex: 4,
child: PublishTimeWidget(
timeAgo: articlesEntity.timeAgo,
),
),
const Spacer(
flex: 2,
),
if (isCategoryIncluded)
const Expanded(
flex: 4,
child: CategoryChip(),
)
else
const SizedBox.shrink(),
],
),
],
);
}
}
Loading

0 comments on commit 2ebcf8b

Please sign in to comment.