diff --git a/asset/lang/en-US.json b/asset/lang/en-US.json index c1ab092..0d44ad2 100644 --- a/asset/lang/en-US.json +++ b/asset/lang/en-US.json @@ -17,5 +17,16 @@ "forgotText":"Forgot Password", "login":"Login", "dontAccount":"Dont have account" + }, + "home":{ + "build":{ + "tabbar":{ + "tab1":"Latest", + "tab2":"Decorative", + "tab3":"Music", + "tab4":"Style" + }, + "subTitle":"Recommended" + } } } \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d4195a9..380d632 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,9 +1,17 @@ PODS: + - device_info (0.0.1): + - Flutter - Flutter (1.0.0) + - path_provider (0.0.1): + - Flutter - path_provider_linux (0.0.1): - Flutter + - path_provider_macos (0.0.1): + - Flutter - path_provider_windows (0.0.1): - Flutter + - share (0.0.1): + - Flutter - shared_preferences (0.0.1): - Flutter - shared_preferences_linux (0.0.1): @@ -14,24 +22,51 @@ PODS: - Flutter - shared_preferences_windows (0.0.1): - Flutter + - url_launcher (0.0.1): + - Flutter + - url_launcher_linux (0.0.1): + - Flutter + - url_launcher_macos (0.0.1): + - Flutter + - url_launcher_web (0.0.1): + - Flutter + - url_launcher_windows (0.0.1): + - Flutter DEPENDENCIES: + - device_info (from `.symlinks/plugins/device_info/ios`) - Flutter (from `Flutter`) + - path_provider (from `.symlinks/plugins/path_provider/ios`) - path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`) + - path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`) - path_provider_windows (from `.symlinks/plugins/path_provider_windows/ios`) + - share (from `.symlinks/plugins/share/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - shared_preferences_linux (from `.symlinks/plugins/shared_preferences_linux/ios`) - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`) - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`) - shared_preferences_windows (from `.symlinks/plugins/shared_preferences_windows/ios`) + - url_launcher (from `.symlinks/plugins/url_launcher/ios`) + - url_launcher_linux (from `.symlinks/plugins/url_launcher_linux/ios`) + - url_launcher_macos (from `.symlinks/plugins/url_launcher_macos/ios`) + - url_launcher_web (from `.symlinks/plugins/url_launcher_web/ios`) + - url_launcher_windows (from `.symlinks/plugins/url_launcher_windows/ios`) EXTERNAL SOURCES: + device_info: + :path: ".symlinks/plugins/device_info/ios" Flutter: :path: Flutter + path_provider: + :path: ".symlinks/plugins/path_provider/ios" path_provider_linux: :path: ".symlinks/plugins/path_provider_linux/ios" + path_provider_macos: + :path: ".symlinks/plugins/path_provider_macos/ios" path_provider_windows: :path: ".symlinks/plugins/path_provider_windows/ios" + share: + :path: ".symlinks/plugins/share/ios" shared_preferences: :path: ".symlinks/plugins/shared_preferences/ios" shared_preferences_linux: @@ -42,16 +77,35 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/shared_preferences_web/ios" shared_preferences_windows: :path: ".symlinks/plugins/shared_preferences_windows/ios" + url_launcher: + :path: ".symlinks/plugins/url_launcher/ios" + url_launcher_linux: + :path: ".symlinks/plugins/url_launcher_linux/ios" + url_launcher_macos: + :path: ".symlinks/plugins/url_launcher_macos/ios" + url_launcher_web: + :path: ".symlinks/plugins/url_launcher_web/ios" + url_launcher_windows: + :path: ".symlinks/plugins/url_launcher_windows/ios" SPEC CHECKSUMS: + device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 + path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0 path_provider_windows: a2b81600c677ac1959367280991971cb9a1edb3b + share: 0b2c3e82132f5888bccca3351c504d0003b3b410 shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d shared_preferences_linux: afefbfe8d921e207f01ede8b60373d9e3b566b78 shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9 shared_preferences_windows: 36b76d6f54e76ead957e60b49e2f124b4cd3e6ae + url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef + url_launcher_linux: ac237cb7a8058736e4aae38bdbcc748a4b394cc0 + url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313 + url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c + url_launcher_windows: 683d7c283894db8d1914d3ab2223b20cc1ad95d5 PODFILE CHECKSUM: c34e2287a9ccaa606aeceab922830efb9a6ff69a diff --git a/lib/core/base/model/base_view_model.dart b/lib/core/base/model/base_view_model.dart index 98c8fe1..b087a3a 100644 --- a/lib/core/base/model/base_view_model.dart +++ b/lib/core/base/model/base_view_model.dart @@ -4,11 +4,13 @@ import '../../init/cache/locale_manager.dart'; import '../../init/navigation/navigation_service.dart'; import '../../init/network/ICoreDio.dart'; import '../../init/network/network_manager.dart'; +import '../../init/network/vexana_manager.dart'; abstract class BaseViewModel { BuildContext context; ICoreDio coreDio = NetworkManager.instance.coreDio; + VexanaManager vexanaManager = VexanaManager.instance; LocaleManager localeManager = LocaleManager.instance; NavigationService navigation = NavigationService.instance; diff --git a/lib/core/components/decoration/circle_decoration.dart b/lib/core/components/decoration/circle_decoration.dart new file mode 100644 index 0000000..9a59865 --- /dev/null +++ b/lib/core/components/decoration/circle_decoration.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class CircleDecoration extends Decoration { + final BoxPainter _painter; + + CircleDecoration({@required Color color, @required double radius}) : _painter = _CirclePainter(color, radius); + + @override + BoxPainter createBoxPainter([onChanged]) => _painter; +} + +class _CirclePainter extends BoxPainter { + final Paint _paint; + final double radius; + + _CirclePainter(Color color, this.radius) + : _paint = Paint() + ..color = color + ..isAntiAlias = true; + + @override + void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) { + final Offset circleOffset = offset + Offset(cfg.size.width / 2, cfg.size.height - radius - 5); + canvas.drawCircle(circleOffset, radius, _paint); + } +} diff --git a/lib/core/init/lang/locale_keys.g.dart b/lib/core/init/lang/locale_keys.g.dart index b27779d..443673f 100644 --- a/lib/core/init/lang/locale_keys.g.dart +++ b/lib/core/init/lang/locale_keys.g.dart @@ -20,5 +20,13 @@ abstract class LocaleKeys { static const login_login = 'login.login'; static const login_dontAccount = 'login.dontAccount'; static const login = 'login'; + static const home_build_tabbar_tab1 = 'home.build.tabbar.tab1'; + static const home_build_tabbar_tab2 = 'home.build.tabbar.tab2'; + static const home_build_tabbar_tab3 = 'home.build.tabbar.tab3'; + static const home_build_tabbar_tab4 = 'home.build.tabbar.tab4'; + static const home_build_tabbar = 'home.build.tabbar'; + static const home_build_subTitle = 'home.build.subTitle'; + static const home_build = 'home.build'; + static const home = 'home'; } diff --git a/lib/core/init/network/vexana_manager.dart b/lib/core/init/network/vexana_manager.dart index 850459a..f770e11 100644 --- a/lib/core/init/network/vexana_manager.dart +++ b/lib/core/init/network/vexana_manager.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:vexana/vexana.dart'; class VexanaManager { @@ -7,7 +9,11 @@ class VexanaManager { return _instace; } + static const String _iosBaseUrl = "http://localhost:3000/"; + static const String _androidBaseUrl = "http://10.0.2.2:3000/"; + VexanaManager._init(); - INetworkManager networkManager = NetworkManager(isEnableLogger: true, options: BaseOptions(baseUrl: "http://localhost:3000/")); + INetworkManager networkManager = + NetworkManager(isEnableLogger: true, options: BaseOptions(baseUrl: Platform.isAndroid ? _androidBaseUrl : _iosBaseUrl)); } diff --git a/lib/core/init/theme/app_theme_light.dart b/lib/core/init/theme/app_theme_light.dart index 4f1f240..28af743 100644 --- a/lib/core/init/theme/app_theme_light.dart +++ b/lib/core/init/theme/app_theme_light.dart @@ -18,6 +18,7 @@ class AppThemeLight extends AppTheme with ILightTheme { fontFamily: ApplicationConstants.FONT_FAMILY, colorScheme: _appColorScheme, textTheme: textTheme(), + appBarTheme: ThemeData.light().appBarTheme.copyWith(brightness: Brightness.light, iconTheme: IconThemeData(color: Colors.black87, size: 21)), inputDecorationTheme: InputDecorationTheme( focusColor: Colors.black12, labelStyle: TextStyle(), @@ -26,18 +27,23 @@ class AppThemeLight extends AppTheme with ILightTheme { focusedBorder: UnderlineInputBorder(borderSide: BorderSide(color: Colors.red))), scaffoldBackgroundColor: Color(0xfff1f3f8), floatingActionButtonTheme: ThemeData.light().floatingActionButtonTheme.copyWith(), - tabBarTheme: tabBarTheme(), + tabBarTheme: tabBarTheme, ); - TabBarTheme tabBarTheme() { + TabBarTheme get tabBarTheme { return TabBarTheme( labelPadding: insets.lowPaddingAll, - unselectedLabelStyle: textThemeLight.headline4.copyWith(color: colorSchemeLight.red), + labelColor: _appColorScheme.onSecondary, + labelStyle: textThemeLight.headline5, + unselectedLabelColor: _appColorScheme.onSecondary.withOpacity(0.2), + // unselectedLabelStyle: textThemeLight.headline4.copyWith(color: colorSchemeLight.red), ); } TextTheme textTheme() { - return TextTheme(headline1: textThemeLight.headline1, headline2: textThemeLight.headline2, overline: textThemeLight.headline3); + return ThemeData.light() + .textTheme + .copyWith(headline1: textThemeLight.headline1, headline2: textThemeLight.headline2, overline: textThemeLight.headline3); } ColorScheme get _appColorScheme { @@ -46,7 +52,7 @@ class AppThemeLight extends AppTheme with ILightTheme { primaryVariant: Colors.white, //xx secondary: Colors.green, secondaryVariant: colorSchemeLight.azure, - surface: Colors.blue, + surface: Colors.blue, //xx background: Colors.white, error: Colors.red[900], onPrimary: Colors.greenAccent, diff --git a/lib/main.dart b/lib/main.dart index 79c0644..4fa98ac 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:fluttermvvmtemplate/view/home/build/feed/view/build_feed_view.dart'; import 'package:provider/provider.dart'; import 'core/constants/app/app_constants.dart'; @@ -25,7 +26,7 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( theme: Provider.of(context, listen: false).currentTheme, - home: LoginView(), + home: BuildFeedView(), onGenerateRoute: NavigationRoute.instance.generateRoute, navigatorKey: NavigationService.instance.navigatorKey, ); diff --git a/lib/view/_product/_utilty/decoration_helper.dart b/lib/view/_product/_utilty/decoration_helper.dart new file mode 100644 index 0000000..2fbb310 --- /dev/null +++ b/lib/view/_product/_utilty/decoration_helper.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; + +import '../../../core/components/decoration/circle_decoration.dart'; +import '../../../core/extension/context_extension.dart'; + +class DecorationHelper { + BuildContext context; + DecorationHelper({ + this.context, + }); + + Decoration get circleDecoriaton => CircleDecoration(color: context.colors.surface, radius: 3); +} diff --git a/lib/view/_product/_utilty/service_helper.dart b/lib/view/_product/_utilty/service_helper.dart new file mode 100644 index 0000000..0dd28c2 --- /dev/null +++ b/lib/view/_product/_utilty/service_helper.dart @@ -0,0 +1,10 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:vexana/vexana.dart'; + +abstract class ServiceHelper { + void showMessage(GlobalKey scaffoldKey, IErrorModel errorModel) { + if (scaffoldKey == null || errorModel == null) return; + scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(errorModel.description ?? errorModel.statusCode.toString()))); + } +} diff --git a/lib/view/_product/_widgets/card/build_user_card.dart b/lib/view/_product/_widgets/card/build_user_card.dart new file mode 100644 index 0000000..8305b02 --- /dev/null +++ b/lib/view/_product/_widgets/card/build_user_card.dart @@ -0,0 +1,50 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/material.dart'; +import 'package:kartal/kartal.dart'; + +import '../../../home/build/feed/model/house_model.dart'; + +class BuildUserCard extends StatelessWidget { + final HouseModel model; + final bool isLiked; + final Function(String id) onPressedLikeId; + + const BuildUserCard({Key key, @required this.model, this.onPressedLikeId, this.isLiked = false}) : super(key: key); + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListTile( + contentPadding: EdgeInsets.zero, + leading: CircleAvatar(backgroundImage: NetworkImage(model.user.image)), + title: Text(model.user.name), + subtitle: Text(model.user.date), + trailing: buildIconButton(), + ), + context.emptySizedHeightBoxLow, + buildWrap(context) + ], + ); + } + + Widget buildWrap(BuildContext context) { + return Column( + children: [ + AutoSizeText(model.title, style: context.textTheme.headline6.copyWith(fontWeight: FontWeight.w600), maxLines: 1), + Text(model.description), + ], + ); + } + + IconButton buildIconButton() { + return IconButton( + icon: Icon( + Icons.favorite, + color: isLiked ? Colors.pink : Colors.black12, + ), + onPressed: () { + onPressedLikeId(model.id); + }); + } +} diff --git a/lib/view/_product/enum/network_route_enum.dart b/lib/view/_product/enum/network_route_enum.dart index 871814f..064edbd 100644 --- a/lib/view/_product/enum/network_route_enum.dart +++ b/lib/view/_product/enum/network_route_enum.dart @@ -1,10 +1,12 @@ -enum NetworkRoutes { LOGIN } +enum NetworkRoutes { LOGIN, BUILD_HOME } extension NetwrokRoutesString on NetworkRoutes { String get rawValue { switch (this) { case NetworkRoutes.LOGIN: return "login"; + case NetworkRoutes.BUILD_HOME: + return "house"; default: throw Exception("Routes Not FouND"); } diff --git a/lib/view/home/build/feed/model/house_model.dart b/lib/view/home/build/feed/model/house_model.dart new file mode 100644 index 0000000..b35fb9b --- /dev/null +++ b/lib/view/home/build/feed/model/house_model.dart @@ -0,0 +1,51 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:vexana/vexana.dart'; + +part 'house_model.g.dart'; + +@JsonSerializable() +class HouseModel extends INetworkModel { + @JsonKey(name: "_id") + String id; + String title; + String description; + String image; + UserHouse user; + int iV; + + HouseModel({this.id, this.title, this.description, this.image, this.user, this.iV}); + + @override + HouseModel fromJson(Map json) { + return _$HouseModelFromJson(json); + } + + @override + Map toJson() { + return _$HouseModelToJson(this); + } +} + +@JsonSerializable() +class UserHouse extends INetworkModel { + @JsonKey(name: "_id") + String id; + String name; + String image; + String date; + + UserHouse({this.id, this.name, this.image, this.date}); + + @override + UserHouse fromJson(Map json) { + return _$UserHouseFromJson(json); + } + + factory UserHouse.fromJson(Map json) { + return _$UserHouseFromJson(json); + } + @override + Map toJson() { + return _$UserHouseToJson(this); + } +} diff --git a/lib/view/home/build/feed/model/house_model.g.dart b/lib/view/home/build/feed/model/house_model.g.dart new file mode 100644 index 0000000..6c2395c --- /dev/null +++ b/lib/view/home/build/feed/model/house_model.g.dart @@ -0,0 +1,46 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'house_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +HouseModel _$HouseModelFromJson(Map json) { + return HouseModel( + id: json['_id'] as String, + title: json['title'] as String, + description: json['description'] as String, + image: json['image'] as String, + user: json['user'] == null + ? null + : UserHouse.fromJson(json['user'] as Map), + iV: json['iV'] as int, + ); +} + +Map _$HouseModelToJson(HouseModel instance) => + { + '_id': instance.id, + 'title': instance.title, + 'description': instance.description, + 'image': instance.image, + 'user': instance.user, + 'iV': instance.iV, + }; + +UserHouse _$UserHouseFromJson(Map json) { + return UserHouse( + id: json['_id'] as String, + name: json['name'] as String, + image: json['image'] as String, + date: json['date'] as String, + ); +} + +Map _$UserHouseToJson(UserHouse instance) => { + '_id': instance.id, + 'name': instance.name, + 'image': instance.image, + 'date': instance.date, + }; diff --git a/lib/view/home/build/feed/service/IBuildFeedService.dart b/lib/view/home/build/feed/service/IBuildFeedService.dart new file mode 100644 index 0000000..3f97b1c --- /dev/null +++ b/lib/view/home/build/feed/service/IBuildFeedService.dart @@ -0,0 +1,14 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:vexana/vexana.dart'; + +import '../model/house_model.dart'; + +abstract class IBuildFeedService { + final INetworkManager manager; + final GlobalKey scaffoldyKey; + + IBuildFeedService(this.manager, this.scaffoldyKey); + + Future> fetchUserHouseList(); +} diff --git a/lib/view/home/build/feed/service/build_feed_service.dart b/lib/view/home/build/feed/service/build_feed_service.dart new file mode 100644 index 0000000..6c37da6 --- /dev/null +++ b/lib/view/home/build/feed/service/build_feed_service.dart @@ -0,0 +1,20 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:vexana/vexana.dart'; + +import '../../../../_product/_utilty/service_helper.dart'; +import '../../../../_product/enum/network_route_enum.dart'; +import '../model/house_model.dart'; +import 'IBuildFeedService.dart'; + +class BuildFeedService extends IBuildFeedService with ServiceHelper { + BuildFeedService(INetworkManager manager, GlobalKey key) : super(manager, key); + + @override + Future> fetchUserHouseList() async { + final response = + await manager.fetch>(NetworkRoutes.BUILD_HOME.rawValue, parseModel: HouseModel(), method: RequestType.GET); + showMessage(scaffoldyKey, response.error); + return response.data; + } +} diff --git a/lib/view/home/build/feed/view/build_feed_view.dart b/lib/view/home/build/feed/view/build_feed_view.dart new file mode 100644 index 0000000..7f36d70 --- /dev/null +++ b/lib/view/home/build/feed/view/build_feed_view.dart @@ -0,0 +1,141 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:kartal/kartal.dart'; + +import '../../../../../core/base/view/base_widget.dart'; +import '../../../../../core/init/lang/locale_keys.g.dart'; +import '../../../../_product/_widgets/card/build_user_card.dart'; +import '../model/house_model.dart'; +import '../viewmodel/build_feed_view_model.dart'; + +class BuildFeedView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return BaseView( + viewModel: BuildFeedViewModel(), + onModelReady: (model) { + model.setContext(context); + model.init(); + model.getListAll(); + }, + onPageBuilder: (BuildContext context, BuildFeedViewModel viewModel) => Scaffold( + key: viewModel.scaffoldKey, + appBar: buildAppBar(), + body: DefaultTabController( + length: 4, + child: Observer(builder: (_) { + return viewModel.isLoaindg + ? buildCenter() + : viewModel.houseModels == null || viewModel.houseModels.isEmpty + ? Center(child: Text("Not Found")) + : buildListViewRecommended(viewModel, context); + })), + ), + ); + } + + ListView buildListViewRecommended(BuildFeedViewModel viewModel, BuildContext context) { + return ListView( + padding: context.paddingLow, + children: [ + buildTabBar(viewModel), + buildSizedBoxLAtestPageView(context, viewModel), + context.emptySizedHeightBoxLow, + Text(LocaleKeys.home_build_subTitle.tr(), style: context.textTheme.headline5.copyWith(fontWeight: FontWeight.w600)), + context.emptySizedHeightBoxLow, + buildListBottom(viewModel) + ], + ); + } + + ListView buildListBottom(BuildFeedViewModel viewModel) { + return ListView.builder( + physics: NeverScrollableScrollPhysics(), + itemBuilder: (context, index) => SizedBox( + height: context.dynamicHeight(0.15), + child: Card( + child: Row( + children: [ + Expanded(flex: 3, child: Image.network(viewModel.houseModels[index].image)), + Expanded(flex: 9, child: buildObserver(viewModel, index)), + ], + ), + )), + itemCount: 3, + shrinkWrap: true, + ); + } + + Observer buildObserver(BuildFeedViewModel viewModel, int index) { + return Observer(builder: (_) { + return BuildUserCard( + model: viewModel.houseModels[index], + isLiked: viewModel.likeItems.contains(viewModel.houseModels[index].id), + onPressedLikeId: (id) { + viewModel.onLikeItemPressed(id); + }, + ); + }); + } + + SizedBox buildSizedBoxLAtestPageView(BuildContext context, BuildFeedViewModel viewModel) { + return SizedBox( + height: context.dynamicHeight(0.3), + child: PageView.builder( + controller: PageController(viewportFraction: 0.95), + itemBuilder: (context, index) => buildStackFloaty(context, viewModel.sliderHouse, viewModel), + itemCount: 3, + ), + ); + } + + TabBar buildTabBar(BuildFeedViewModel viewModel) { + return TabBar(indicator: viewModel.helper.circleDecoriaton, indicatorSize: TabBarIndicatorSize.label, tabs: [ + Tab(text: LocaleKeys.home_build_tabbar_tab1.tr()), + Tab(text: LocaleKeys.home_build_tabbar_tab2.tr()), + Tab(text: LocaleKeys.home_build_tabbar_tab3.tr()), + Tab(text: LocaleKeys.home_build_tabbar_tab4.tr()), + ]); + } + + Center buildCenter() => Center(child: CircularProgressIndicator()); + + AppBar buildAppBar() { + return AppBar( + backgroundColor: Colors.transparent, + elevation: 0, + leading: IconButton(icon: Icon(Icons.format_align_left), onPressed: () {}), + actions: [IconButton(icon: Icon(Icons.search), onPressed: () {})], + ); + } + + Widget buildStackFloaty(BuildContext context, HouseModel model, BuildFeedViewModel viewModel) { + return Padding( + padding: EdgeInsets.only(right: context.lowValue), + child: Stack( + children: [ + Positioned.fill(bottom: 100, left: -50, right: -50, child: Image.network(model.image, fit: BoxFit.cover)), + Positioned(top: 120, left: 10, right: 10, child: buildCardFloaty(context, model, viewModel)) + ], + ), + ); + } + + Card buildCardFloaty(BuildContext context, HouseModel model, BuildFeedViewModel viewModel) { + return Card( + child: Padding( + padding: context.paddingLow, + child: Observer(builder: (_) { + return BuildUserCard( + model: model, + isLiked: viewModel.likeItems.contains(model.id), + onPressedLikeId: (id) { + viewModel.onLikeItemPressed(id); + }, + ); + }), + ), + ); + } +} diff --git a/lib/view/home/build/feed/viewmodel/build_feed_view_model.dart b/lib/view/home/build/feed/viewmodel/build_feed_view_model.dart new file mode 100644 index 0000000..8e04bc3 --- /dev/null +++ b/lib/view/home/build/feed/viewmodel/build_feed_view_model.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:mobx/mobx.dart'; + +import '../../../../../core/base/model/base_view_model.dart'; +import '../../../../_product/_utilty/decoration_helper.dart'; +import '../model/house_model.dart'; +import '../service/IBuildFeedService.dart'; +import '../service/build_feed_service.dart'; + +part 'build_feed_view_model.g.dart'; + +class BuildFeedViewModel = _BuildFeedViewModelBase with _$BuildFeedViewModel; + +abstract class _BuildFeedViewModelBase with Store, BaseViewModel { + void setContext(BuildContext context) => this.context = context; + + GlobalKey scaffoldKey = GlobalKey(); + DecorationHelper helper; + IBuildFeedService feedService; + @observable + List likeItems = []; + + @action + void onLikeItemPressed(String id) { + if (likeItems.contains(id)) { + likeItems.remove(id); + } else { + likeItems.add(id); + } + + likeItems = likeItems; + } + + @observable + List houseModels = []; + + @computed + HouseModel get sliderHouse => houseModels.first; + + @observable + bool isLoaindg = false; + + void init() { + helper = DecorationHelper(context: context); + feedService = BuildFeedService(vexanaManager.networkManager, scaffoldKey); + } + + @action + void _changeLoading() { + isLoaindg = !isLoaindg; + } + + @action + Future getListAll() async { + _changeLoading(); + houseModels = await feedService.fetchUserHouseList(); + + _changeLoading(); + } +} diff --git a/lib/view/home/build/feed/viewmodel/build_feed_view_model.g.dart b/lib/view/home/build/feed/viewmodel/build_feed_view_model.g.dart new file mode 100644 index 0000000..35371f3 --- /dev/null +++ b/lib/view/home/build/feed/viewmodel/build_feed_view_model.g.dart @@ -0,0 +1,107 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'build_feed_view_model.dart'; + +// ************************************************************************** +// StoreGenerator +// ************************************************************************** + +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic + +mixin _$BuildFeedViewModel on _BuildFeedViewModelBase, Store { + Computed _$sliderHouseComputed; + + @override + HouseModel get sliderHouse => + (_$sliderHouseComputed ??= Computed(() => super.sliderHouse, + name: '_BuildFeedViewModelBase.sliderHouse')) + .value; + + final _$likeItemsAtom = Atom(name: '_BuildFeedViewModelBase.likeItems'); + + @override + List get likeItems { + _$likeItemsAtom.reportRead(); + return super.likeItems; + } + + @override + set likeItems(List value) { + _$likeItemsAtom.reportWrite(value, super.likeItems, () { + super.likeItems = value; + }); + } + + final _$houseModelsAtom = Atom(name: '_BuildFeedViewModelBase.houseModels'); + + @override + List get houseModels { + _$houseModelsAtom.reportRead(); + return super.houseModels; + } + + @override + set houseModels(List value) { + _$houseModelsAtom.reportWrite(value, super.houseModels, () { + super.houseModels = value; + }); + } + + final _$isLoaindgAtom = Atom(name: '_BuildFeedViewModelBase.isLoaindg'); + + @override + bool get isLoaindg { + _$isLoaindgAtom.reportRead(); + return super.isLoaindg; + } + + @override + set isLoaindg(bool value) { + _$isLoaindgAtom.reportWrite(value, super.isLoaindg, () { + super.isLoaindg = value; + }); + } + + final _$getListAllAsyncAction = + AsyncAction('_BuildFeedViewModelBase.getListAll'); + + @override + Future getListAll() { + return _$getListAllAsyncAction.run(() => super.getListAll()); + } + + final _$_BuildFeedViewModelBaseActionController = + ActionController(name: '_BuildFeedViewModelBase'); + + @override + void onLikeItemPressed(String id) { + final _$actionInfo = _$_BuildFeedViewModelBaseActionController.startAction( + name: '_BuildFeedViewModelBase.onLikeItemPressed'); + try { + return super.onLikeItemPressed(id); + } finally { + _$_BuildFeedViewModelBaseActionController.endAction(_$actionInfo); + } + } + + @override + void _changeLoading() { + final _$actionInfo = _$_BuildFeedViewModelBaseActionController.startAction( + name: '_BuildFeedViewModelBase._changeLoading'); + try { + return super._changeLoading(); + } finally { + _$_BuildFeedViewModelBaseActionController.endAction(_$actionInfo); + } + } + + @override + String toString() { + return ''' +likeItems: ${likeItems}, +houseModels: ${houseModels}, +isLoaindg: ${isLoaindg}, +sliderHouse: ${sliderHouse} + '''; + } +} diff --git a/pubspec.lock b/pubspec.lock index 1fdca18..4b74f92 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -176,6 +176,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.10" + device_info: + dependency: transitive + description: + name: device_info + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + device_info_platform_interface: + dependency: transitive + description: + name: device_info_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" dio: dependency: "direct main" description: @@ -315,6 +329,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.5.1" + kartal: + dependency: "direct main" + description: + name: kartal + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" logging: dependency: transitive description: @@ -322,6 +343,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.11.4" + mask_text_input_formatter: + dependency: transitive + description: + name: mask_text_input_formatter + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" matcher: dependency: transitive description: @@ -511,6 +539,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.5" + share: + dependency: transitive + description: + name: share + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.5+4" shared_preferences: dependency: "direct main" description: @@ -642,6 +677,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.3" + url_launcher: + dependency: transitive + description: + name: url_launcher + url: "https://pub.dartlang.org" + source: hosted + version: "5.7.10" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+4" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+9" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.9" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.5+1" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+3" vector_math: dependency: transitive description: @@ -700,4 +777,4 @@ packages: version: "2.2.1" sdks: dart: ">=2.10.0 <2.11.0" - flutter: ">=1.18.0-6.0.pre <2.0.0" + flutter: ">=1.22.0 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 4f544cc..f324326 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,7 @@ dependencies: flutter_svg: any json_annotation: ^3.0.1 json_serializable: ^3.3.0 + kartal: ^1.1.0 mobx: ^1.2.1 mobx_codegen: ^1.1.0 provider: ^4.1.3