├── lib ├── utils │ ├── services │ │ └── services.dart │ ├── ext │ │ ├── ext.dart │ │ ├── double.dart │ │ └── context.dart │ ├── helper │ │ ├── helper.dart │ │ ├── common.dart │ │ └── constant.dart │ └── utils.dart ├── core │ ├── core.dart │ └── localization │ │ ├── localization.dart │ │ ├── l10n.dart │ │ ├── intl_en.arb │ │ └── intl_id.arb ├── data │ ├── data.dart │ └── datasources │ │ ├── datasources.dart │ │ └── local │ │ ├── local.dart │ │ ├── data_helper.dart │ │ ├── pref_manager.dart │ │ └── portfolio_response.dart ├── presentation │ ├── pages │ │ ├── pages.dart │ │ ├── main │ │ │ ├── home │ │ │ │ ├── home.dart │ │ │ │ ├── home_title.dart │ │ │ │ ├── home_description.dart │ │ │ │ └── home_section.dart │ │ │ ├── services │ │ │ │ ├── services.dart │ │ │ │ ├── services_title.dart │ │ │ │ ├── services_section.dart │ │ │ │ └── services_description.dart │ │ │ ├── portfolio │ │ │ │ ├── portfolio.dart │ │ │ │ ├── portfolio_title.dart │ │ │ │ └── portfolio_section.dart │ │ │ ├── profile │ │ │ │ ├── profile.dart │ │ │ │ ├── profile_title.dart │ │ │ │ ├── profile_button.dart │ │ │ │ ├── profile_section.dart │ │ │ │ └── profile_description.dart │ │ │ ├── main.dart │ │ │ ├── main_cubit.dart │ │ │ ├── footer_copy_right.dart │ │ │ ├── main_menu.dart │ │ │ ├── main_popup_menu.dart │ │ │ ├── footer.dart │ │ │ ├── main_page.dart │ │ │ └── main_drawer.dart │ │ └── app_route.dart │ ├── presentation.dart │ ├── resources │ │ ├── resources.dart │ │ ├── images.dart │ │ ├── dimens.dart │ │ ├── palette.dart │ │ └── styles.dart │ └── widgets │ │ ├── spacer_h.dart │ │ ├── spacer_v.dart │ │ ├── widgets.dart │ │ ├── indicator_slider.dart │ │ ├── circle_image.dart │ │ ├── image_network.dart │ │ ├── parent.dart │ │ ├── animated_mouse.dart │ │ ├── animated_box_slider.dart │ │ ├── scroll_indicator.dart │ │ ├── animated_widget_slider.dart │ │ ├── responsive.dart │ │ ├── animated_widget_shape.dart │ │ ├── animated_text_strikethrough.dart │ │ ├── animated_text_box.dart │ │ └── animated_button.dart ├── di │ └── di.dart └── main.dart ├── web ├── fav │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── mstile-150x150.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── browserconfig.xml │ ├── site.webmanifest │ └── safari-pinned-tab.svg ├── manifest.json └── index.html ├── assets ├── fonts │ ├── Circe.otf │ └── visuelt │ │ ├── VisueltPro-Black.ttf │ │ ├── VisueltPro-Bold.ttf │ │ ├── VisueltPro-Italic.ttf │ │ ├── VisueltPro-Light.ttf │ │ ├── VisueltPro-Medium.ttf │ │ ├── VisueltPro-Thin.ttf │ │ ├── VisueltPro-Regular.ttf │ │ ├── VisueltPro-BlackItalic.ttf │ │ ├── VisueltPro-BoldItalic.ttf │ │ ├── VisueltPro-ExtraLight.ttf │ │ ├── VisueltPro-LightItalic.ttf │ │ ├── VisueltPro-ThinItalic.ttf │ │ ├── VisueltPro-MediumItalic.ttf │ │ └── VisueltPro-ExtraLightItalic.ttf ├── images │ ├── ic_avatar.png │ ├── ic_launcher.jpg │ ├── ic_profile.jpg │ ├── ic_playstore.png │ ├── ic_launcher_staging.jpg │ ├── portfolio │ │ ├── oifyoo │ │ │ ├── image_1.png │ │ │ ├── image_2.png │ │ │ ├── image_3.png │ │ │ ├── image_4.png │ │ │ └── image_5.png │ │ ├── brupedia │ │ │ ├── image_1.png │ │ │ ├── image_2.png │ │ │ └── image_3.png │ │ ├── eabsensi │ │ │ ├── image_1.png │ │ │ ├── image_2.png │ │ │ ├── image_3.png │ │ │ └── image_4.png │ │ ├── myananda │ │ │ ├── image_1.png │ │ │ ├── image_2.png │ │ │ ├── image_3.png │ │ │ ├── image_4.png │ │ │ └── image_5.png │ │ ├── wautils │ │ │ ├── image_1.png │ │ │ ├── image_2.png │ │ │ ├── image_3.png │ │ │ └── image_4.png │ │ ├── pataparking │ │ │ ├── image_1.png │ │ │ ├── image_2.png │ │ │ └── image_3.png │ │ └── patapaowners │ │ │ ├── image_1.png │ │ │ ├── image_2.png │ │ │ └── image_3.png │ ├── ic_facebook.svg │ ├── ic_youtube.svg │ ├── ic_upwork.svg │ ├── ic_linkedin.svg │ ├── ic_menu.svg │ ├── ic_close.svg │ ├── ic_github.svg │ ├── ic_tiktok.svg │ ├── ic_logo.svg │ ├── ic_settings.svg │ └── ic_instagram.svg └── static_api │ ├── portfolio_en.json │ └── portfolio_id.json ├── analysis_options.yaml ├── l10n.yaml ├── .gitignore └── pubspec.yaml /lib/utils/services/services.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/core/core.dart: -------------------------------------------------------------------------------- 1 | export 'localization/localization.dart'; 2 | -------------------------------------------------------------------------------- /lib/data/data.dart: -------------------------------------------------------------------------------- 1 | export 'datasources/datasources.dart'; 2 | -------------------------------------------------------------------------------- /lib/data/datasources/datasources.dart: -------------------------------------------------------------------------------- 1 | export 'local/local.dart'; 2 | -------------------------------------------------------------------------------- /lib/utils/ext/ext.dart: -------------------------------------------------------------------------------- 1 | export 'context.dart'; 2 | export 'double.dart'; 3 | -------------------------------------------------------------------------------- /lib/utils/helper/helper.dart: -------------------------------------------------------------------------------- 1 | export 'common.dart'; 2 | export 'constant.dart'; 3 | -------------------------------------------------------------------------------- /lib/presentation/pages/pages.dart: -------------------------------------------------------------------------------- 1 | export 'app_route.dart'; 2 | export 'main/main.dart'; 3 | -------------------------------------------------------------------------------- /lib/core/localization/localization.dart: -------------------------------------------------------------------------------- 1 | export 'generated/strings.dart'; 2 | export 'l10n.dart'; 3 | -------------------------------------------------------------------------------- /web/fav/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/web/fav/favicon.ico -------------------------------------------------------------------------------- /assets/fonts/Circe.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/Circe.otf -------------------------------------------------------------------------------- /lib/utils/utils.dart: -------------------------------------------------------------------------------- 1 | export 'ext/ext.dart'; 2 | export 'helper/helper.dart'; 3 | export 'services/services.dart'; 4 | -------------------------------------------------------------------------------- /assets/images/ic_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/ic_avatar.png -------------------------------------------------------------------------------- /web/fav/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/web/fav/favicon-16x16.png -------------------------------------------------------------------------------- /web/fav/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/web/fav/favicon-32x32.png -------------------------------------------------------------------------------- /web/fav/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/web/fav/mstile-150x150.png -------------------------------------------------------------------------------- /assets/images/ic_launcher.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/ic_launcher.jpg -------------------------------------------------------------------------------- /assets/images/ic_profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/ic_profile.jpg -------------------------------------------------------------------------------- /web/fav/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/web/fav/apple-touch-icon.png -------------------------------------------------------------------------------- /assets/images/ic_playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/ic_playstore.png -------------------------------------------------------------------------------- /lib/utils/ext/double.dart: -------------------------------------------------------------------------------- 1 | extension DoubleExtension on double { 2 | bool isVisible() { 3 | return this > 80; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /lib/data/datasources/local/local.dart: -------------------------------------------------------------------------------- 1 | export 'data_helper.dart'; 2 | export 'portfolio_response.dart'; 3 | export 'pref_manager.dart'; 4 | -------------------------------------------------------------------------------- /web/fav/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/web/fav/android-chrome-192x192.png -------------------------------------------------------------------------------- /web/fav/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/web/fav/android-chrome-512x512.png -------------------------------------------------------------------------------- /assets/images/ic_launcher_staging.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/ic_launcher_staging.jpg -------------------------------------------------------------------------------- /lib/presentation/pages/main/home/home.dart: -------------------------------------------------------------------------------- 1 | export 'home_description.dart'; 2 | export 'home_section.dart'; 3 | export 'home_title.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/presentation.dart: -------------------------------------------------------------------------------- 1 | export 'pages/pages.dart'; 2 | export 'resources/resources.dart'; 3 | export 'widgets/widgets.dart'; 4 | -------------------------------------------------------------------------------- /lib/presentation/resources/resources.dart: -------------------------------------------------------------------------------- 1 | export 'dimens.dart'; 2 | export 'images.dart'; 3 | export 'palette.dart'; 4 | export 'styles.dart'; 5 | -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-Black.ttf -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-Italic.ttf -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-Light.ttf -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-Medium.ttf -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-Thin.ttf -------------------------------------------------------------------------------- /assets/images/portfolio/oifyoo/image_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/oifyoo/image_1.png -------------------------------------------------------------------------------- /assets/images/portfolio/oifyoo/image_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/oifyoo/image_2.png -------------------------------------------------------------------------------- /assets/images/portfolio/oifyoo/image_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/oifyoo/image_3.png -------------------------------------------------------------------------------- /assets/images/portfolio/oifyoo/image_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/oifyoo/image_4.png -------------------------------------------------------------------------------- /assets/images/portfolio/oifyoo/image_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/oifyoo/image_5.png -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-Regular.ttf -------------------------------------------------------------------------------- /assets/images/portfolio/brupedia/image_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/brupedia/image_1.png -------------------------------------------------------------------------------- /assets/images/portfolio/brupedia/image_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/brupedia/image_2.png -------------------------------------------------------------------------------- /assets/images/portfolio/brupedia/image_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/brupedia/image_3.png -------------------------------------------------------------------------------- /assets/images/portfolio/eabsensi/image_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/eabsensi/image_1.png -------------------------------------------------------------------------------- /assets/images/portfolio/eabsensi/image_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/eabsensi/image_2.png -------------------------------------------------------------------------------- /assets/images/portfolio/eabsensi/image_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/eabsensi/image_3.png -------------------------------------------------------------------------------- /assets/images/portfolio/eabsensi/image_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/eabsensi/image_4.png -------------------------------------------------------------------------------- /assets/images/portfolio/myananda/image_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/myananda/image_1.png -------------------------------------------------------------------------------- /assets/images/portfolio/myananda/image_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/myananda/image_2.png -------------------------------------------------------------------------------- /assets/images/portfolio/myananda/image_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/myananda/image_3.png -------------------------------------------------------------------------------- /assets/images/portfolio/myananda/image_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/myananda/image_4.png -------------------------------------------------------------------------------- /assets/images/portfolio/myananda/image_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/myananda/image_5.png -------------------------------------------------------------------------------- /assets/images/portfolio/wautils/image_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/wautils/image_1.png -------------------------------------------------------------------------------- /assets/images/portfolio/wautils/image_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/wautils/image_2.png -------------------------------------------------------------------------------- /assets/images/portfolio/wautils/image_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/wautils/image_3.png -------------------------------------------------------------------------------- /assets/images/portfolio/wautils/image_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/wautils/image_4.png -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lint/analysis_options.yaml 2 | linter: 3 | rules: 4 | sort_pub_dependencies: false 5 | avoid_dynamic_calls: false -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-BlackItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-BoldItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-ExtraLight.ttf -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-LightItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-ThinItalic.ttf -------------------------------------------------------------------------------- /assets/images/portfolio/pataparking/image_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/pataparking/image_1.png -------------------------------------------------------------------------------- /assets/images/portfolio/pataparking/image_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/pataparking/image_2.png -------------------------------------------------------------------------------- /assets/images/portfolio/pataparking/image_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/pataparking/image_3.png -------------------------------------------------------------------------------- /lib/presentation/pages/main/services/services.dart: -------------------------------------------------------------------------------- 1 | export 'services_description.dart'; 2 | export 'services_section.dart'; 3 | export 'services_title.dart'; 4 | -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-MediumItalic.ttf -------------------------------------------------------------------------------- /assets/images/portfolio/patapaowners/image_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/patapaowners/image_1.png -------------------------------------------------------------------------------- /assets/images/portfolio/patapaowners/image_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/patapaowners/image_2.png -------------------------------------------------------------------------------- /assets/images/portfolio/patapaowners/image_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/images/portfolio/patapaowners/image_3.png -------------------------------------------------------------------------------- /lib/presentation/pages/main/portfolio/portfolio.dart: -------------------------------------------------------------------------------- 1 | export 'portfolio_description.dart'; 2 | export 'portfolio_section.dart'; 3 | export 'portfolio_title.dart'; 4 | -------------------------------------------------------------------------------- /assets/fonts/visuelt/VisueltPro-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatlabs/flutter-web-portfolio/HEAD/assets/fonts/visuelt/VisueltPro-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /lib/presentation/pages/main/profile/profile.dart: -------------------------------------------------------------------------------- 1 | export 'profile_button.dart'; 2 | export 'profile_description.dart'; 3 | export 'profile_section.dart'; 4 | export 'profile_title.dart'; 5 | -------------------------------------------------------------------------------- /l10n.yaml: -------------------------------------------------------------------------------- 1 | arb-dir: lib/core/localization 2 | output-dir: lib/core/localization/generated 3 | template-arb-file: intl_en.arb 4 | output-localization-file: strings.dart 5 | output-class: Strings 6 | synthetic-package: false -------------------------------------------------------------------------------- /web/fav/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/core/localization/l10n.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class L10n { 4 | L10n._(); 5 | 6 | static final all = [ 7 | const Locale('en'), 8 | const Locale('id'), 9 | ]; 10 | 11 | static String getFlag(String code) { 12 | switch (code) { 13 | case 'id': 14 | return 'Bahasa'; 15 | case 'en': 16 | default: 17 | return 'English'; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/presentation/widgets/spacer_h.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | 4 | class SpacerH extends StatelessWidget { 5 | const SpacerH({super.key, this.value}); 6 | 7 | final double? value; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | width: value ?? Dimens.space8, 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/presentation/widgets/spacer_v.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | 4 | class SpacerV extends StatelessWidget { 5 | const SpacerV({super.key, this.value}); 6 | 7 | final double? value; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return SizedBox( 12 | height: value ?? Dimens.space8, 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/main.dart: -------------------------------------------------------------------------------- 1 | export 'footer.dart'; 2 | export 'footer_copy_right.dart'; 3 | export 'home/home.dart'; 4 | export 'main_cubit.dart'; 5 | export 'main_drawer.dart'; 6 | export 'main_menu.dart'; 7 | export 'main_page.dart'; 8 | export 'main_popup_menu.dart'; 9 | export 'portfolio/portfolio.dart'; 10 | export 'profile/profile.dart'; 11 | export 'profile/profile_button.dart'; 12 | export 'services/services.dart'; 13 | -------------------------------------------------------------------------------- /web/fav/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /lib/presentation/widgets/widgets.dart: -------------------------------------------------------------------------------- 1 | export 'animated_box_slider.dart'; 2 | export 'animated_button.dart'; 3 | export 'animated_mouse.dart'; 4 | export 'animated_text_box.dart'; 5 | export 'animated_text_strikethrough.dart'; 6 | export 'animated_widget_shape.dart'; 7 | export 'animated_widget_slider.dart'; 8 | export 'circle_image.dart'; 9 | export 'image_network.dart'; 10 | export 'indicator_slider.dart'; 11 | export 'parent.dart'; 12 | export 'responsive.dart'; 13 | export 'scroll_indicator.dart'; 14 | export 'spacer_h.dart'; 15 | export 'spacer_v.dart'; 16 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "start_url": "/", 3 | "orientation": "portrait-primary", 4 | "prefer_related_applications": false, 5 | "name": "lazycatlabs", 6 | "short_name": "lazycatlabs", 7 | "icons": [ 8 | { 9 | "src": "fav/android-chrome-192x192.png", 10 | "sizes": "192x192", 11 | "type": "image/png" 12 | }, 13 | { 14 | "src": "fav/android-chrome-512x512.png", 15 | "sizes": "512x512", 16 | "type": "image/png" 17 | } 18 | ], 19 | "theme_color": "#ffffff", 20 | "background_color": "#ffffff", 21 | "display": "standalone" 22 | } 23 | -------------------------------------------------------------------------------- /assets/images/ic_facebook.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/main_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_bloc/flutter_bloc.dart'; 2 | import 'package:lazycatlabs/data/datasources/datasources.dart'; 3 | import 'package:lazycatlabs/di/di.dart'; 4 | 5 | class MainCubit extends Cubit { 6 | MainCubit() : super(DataHelper(type: "en")); 7 | 8 | void updateTheme(ActiveTheme activeTheme) { 9 | sl().theme = activeTheme.name; 10 | emit(DataHelper(activeTheme: activeTheme, type: sl().locale)); 11 | } 12 | 13 | void updateLanguage(String type) { 14 | /// Update locale code 15 | sl().locale = type; 16 | emit(DataHelper(type: type, activeTheme: getActiveTheme())); 17 | } 18 | 19 | ActiveTheme getActiveTheme() { 20 | return ActiveTheme.values 21 | .firstWhere((element) => element.name == sl().theme); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /assets/images/ic_youtube.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | lib/core/localization/generated 34 | 35 | # Web related 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Exceptions to above rules. 44 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 45 | 46 | .metadata 47 | pubspec.lock 48 | -------------------------------------------------------------------------------- /lib/presentation/pages/app_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:go_router/go_router.dart'; 4 | import 'package:lazycatlabs/presentation/pages/pages.dart'; 5 | 6 | enum Routes { 7 | root("/"), 8 | ; 9 | 10 | const Routes(this.path); 11 | 12 | final String path; 13 | } 14 | 15 | class AppRoute { 16 | static late BuildContext context; 17 | 18 | AppRoute.setStream(BuildContext ctx) { 19 | context = ctx; 20 | } 21 | 22 | static final GoRouter router = GoRouter( 23 | routes: [ 24 | GoRoute( 25 | path: Routes.root.path, 26 | name: Routes.root.name, 27 | builder: (_, state) { 28 | return MainPage( 29 | key: state.pageKey, 30 | ); 31 | }, 32 | ), 33 | ], 34 | initialLocation: Routes.root.path, 35 | routerNeglect: true, 36 | debugLogDiagnostics: kDebugMode, 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /lib/presentation/widgets/indicator_slider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | 4 | // ignore: must_be_immutable 5 | class IndicatorSlider extends StatelessWidget { 6 | final bool isActive; 7 | Color? activeColour; 8 | Color? inActiveColour; 9 | 10 | IndicatorSlider({ 11 | super.key, 12 | required this.isActive, 13 | this.activeColour, 14 | this.inActiveColour, 15 | }); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return AnimatedContainer( 20 | duration: const Duration(milliseconds: 500), 21 | margin: EdgeInsets.all(Dimens.space2), 22 | width: isActive ? Dimens.space10 : Dimens.space8, 23 | height: isActive ? Dimens.space10 : Dimens.space8, 24 | decoration: BoxDecoration( 25 | color: isActive 26 | ? activeColour ?? Palette.offWhite 27 | : inActiveColour ?? Palette.offWhite.withOpacity(0.4), 28 | shape: BoxShape.circle, 29 | ), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/di/di.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:get_it/get_it.dart'; 3 | import 'package:lazycatlabs/data/datasources/datasources.dart'; 4 | import 'package:lazycatlabs/presentation/pages/pages.dart'; 5 | import 'package:shared_preferences/shared_preferences.dart'; 6 | 7 | GetIt sl = GetIt.instance; 8 | 9 | Future serviceLocator({bool isUnitTest = false}) async { 10 | /// For unit testing only 11 | if (isUnitTest) { 12 | WidgetsFlutterBinding.ensureInitialized(); 13 | sl.reset(); 14 | // ignore: invalid_use_of_visible_for_testing_member 15 | SharedPreferences.setMockInitialValues({}); 16 | await SharedPreferences.getInstance().then((value) { 17 | initPrefManager(value); 18 | }); 19 | cubit(); 20 | } else { 21 | cubit(); 22 | } 23 | } 24 | 25 | // Register prefManager 26 | void initPrefManager(SharedPreferences initPrefManager) { 27 | sl.registerLazySingleton(() => PrefManager(initPrefManager)); 28 | } 29 | 30 | void cubit() { 31 | sl.registerFactory(() => MainCubit()); 32 | } 33 | -------------------------------------------------------------------------------- /assets/images/ic_upwork.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/ic_linkedin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /lib/presentation/resources/images.dart: -------------------------------------------------------------------------------- 1 | class Images { 2 | Images._(); 3 | 4 | static String icAvatar = "assets/images/ic_avatar.png"; 5 | static String icLogo = "assets/images/ic_logo.svg"; 6 | static String icLogoText = "assets/images/ic_logo_text.svg"; 7 | static String icLogoTextOneline = "assets/images/ic_logo_text_oneline.svg"; 8 | static String icMenu = "assets/images/ic_menu.svg"; 9 | static String icSettings = "assets/images/ic_settings.svg"; 10 | static String icProfile = "assets/images/ic_profile.jpg"; 11 | static String icLinkedIn = "assets/images/ic_linkedin.svg"; 12 | static String icUpwork = "assets/images/ic_upwork.svg"; 13 | static String icGithub = "assets/images/ic_github.svg"; 14 | static String icFacebook = "assets/images/ic_facebook.svg"; 15 | static String icInstagram = "assets/images/ic_instagram.svg"; 16 | static String icTiktok = "assets/images/ic_tiktok.svg"; 17 | static String icYoutube = "assets/images/ic_youtube.svg"; 18 | static String icPlaystore = "assets/images/ic_playstore.png"; 19 | static String icClose = "assets/images/ic_close.svg"; 20 | } 21 | -------------------------------------------------------------------------------- /assets/images/ic_menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /lib/utils/helper/common.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | import 'package:logger/logger.dart'; 4 | 5 | final log = Logger( 6 | printer: PrettyPrinter( 7 | methodCount: 1, 8 | lineLength: 110, 9 | ), 10 | ); 11 | 12 | Size textSize({ 13 | required String text, 14 | required TextStyle? style, 15 | int maxLines = 1, 16 | double maxWidth = double.infinity, 17 | }) { 18 | final TextPainter textPainter = TextPainter( 19 | text: TextSpan(text: text, style: style), 20 | maxLines: maxLines, 21 | textDirection: TextDirection.ltr, 22 | )..layout(maxWidth: maxWidth); 23 | return textPainter.size; 24 | } 25 | 26 | double responsiveSize( 27 | BuildContext context, 28 | double mobile, 29 | double desktop, { 30 | double? tablet, 31 | }) { 32 | if (Responsive.isDesktop(context)) { 33 | return desktop; 34 | } else if (Responsive.isTablet(context)) { 35 | return tablet ?? mobile; 36 | } else { 37 | return mobile; 38 | } 39 | } 40 | 41 | const durationShort = Duration(milliseconds: 400); 42 | const durationLong = Duration(milliseconds: 1500); 43 | -------------------------------------------------------------------------------- /lib/data/datasources/local/data_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/data/datasources/local/pref_manager.dart'; 3 | 4 | class DataHelper { 5 | final String? title; 6 | final String? desc; 7 | bool isSelected; 8 | final String? iconPath; 9 | final IconData? icon; 10 | final String? url; 11 | final String? type; 12 | final int? id; 13 | final ActiveTheme activeTheme; 14 | final AnimationController? animationController; 15 | Animation? animation; 16 | ColorTween? colorTween; 17 | VoidCallback? onPressed; 18 | Color? iconColor; 19 | bool onHover; 20 | 21 | DataHelper({ 22 | this.title, 23 | this.desc, 24 | this.isSelected = false, 25 | this.iconPath, 26 | this.icon, 27 | this.url, 28 | this.type, 29 | this.id, 30 | this.activeTheme = ActiveTheme.system, 31 | this.animationController, 32 | this.animation, 33 | this.colorTween, 34 | this.onPressed, 35 | this.iconColor, 36 | this.onHover = false, 37 | }) { 38 | if (animationController != null && colorTween != null) { 39 | animation = colorTween!.animate(animationController!); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /assets/images/ic_close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/ic_github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /lib/presentation/widgets/circle_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:lazycatlabs/presentation/presentation.dart'; 4 | 5 | ///********************************************* 6 | /// Created by ukietux on 03/11/20 with ♥ 7 | /// (>’_’)> email : ukie.tux@gmail.com 8 | /// github : https://www.github.com/Lzyct <(’_’<) 9 | ///********************************************* 10 | /// © 2020 | All Right Reserved 11 | class CircleImage extends StatelessWidget { 12 | final String url; 13 | final double? size; 14 | 15 | const CircleImage({super.key, required this.url, this.size}); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | /// TODO Need to change with Fix on error image url 20 | return ClipRRect( 21 | borderRadius: BorderRadius.circular(360), 22 | 23 | /// 360 degree circle 24 | child: CachedNetworkImage( 25 | fit: BoxFit.cover, 26 | width: size, 27 | height: size, 28 | fadeInDuration: const Duration(milliseconds: 300), 29 | imageUrl: url, 30 | placeholder: (context, url) => SizedBox( 31 | width: Dimens.space46, 32 | height: Dimens.space46, 33 | child: const CupertinoActivityIndicator(), 34 | ), 35 | // errorWidget: (context, url, error) => 36 | // new SvgPicture.asset(Images.icEmpty), 37 | ), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /assets/images/ic_tiktok.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /lib/presentation/widgets/image_network.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:lazycatlabs/presentation/presentation.dart'; 4 | 5 | ///********************************************* 6 | /// my-ananda-hospital | 7 | /// image_network.dart 8 | /// -------------------------------------------- 9 | /// Created by Mudassir 🧑🏻‍💻 @ >codelogs_ 10 | /// on 📅 08/06/21 🕰 10:10 with ❤️ 11 | /// email : hey.mudassir@gmail.com 12 | /// github : https://www.github.com/Lzyct 13 | ///********************************************* 14 | /// © 2021 | All Right Reserved 15 | class ImageNetwork extends StatelessWidget { 16 | final String imageUrl; 17 | final double? width; 18 | final double? height; 19 | 20 | const ImageNetwork({ 21 | super.key, 22 | required this.imageUrl, 23 | this.width, 24 | this.height, 25 | }); 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | return CachedNetworkImage( 30 | fit: BoxFit.cover, 31 | width: width, 32 | height: height, 33 | fadeInDuration: const Duration(milliseconds: 300), 34 | imageUrl: imageUrl, 35 | placeholder: (context, url) => SizedBox( 36 | width: Dimens.space46, 37 | height: Dimens.space46, 38 | child: const CupertinoActivityIndicator(), 39 | ), 40 | // errorWidget: (context, url, error) => 41 | // new SvgPicture.asset(Images.icEmpty), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/footer_copy_right.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/core/core.dart'; 3 | import 'package:lazycatlabs/presentation/presentation.dart'; 4 | import 'package:lazycatlabs/utils/utils.dart'; 5 | 6 | class FooterCopyRight extends StatelessWidget { 7 | const FooterCopyRight({super.key, required this.context}); 8 | 9 | final BuildContext context; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Container( 14 | color: Theme.of(context).scaffoldBackgroundColor, 15 | width: double.maxFinite, 16 | padding: EdgeInsets.symmetric(vertical: Dimens.space16), 17 | child: Column( 18 | children: [ 19 | Text( 20 | "\u00a9 ${DateTime.now().year} ${Constants.get.appName}", 21 | style: Theme.of(context).textTheme.bodyText2, 22 | ), 23 | Row( 24 | mainAxisSize: MainAxisSize.min, 25 | mainAxisAlignment: MainAxisAlignment.center, 26 | children: [ 27 | Text( 28 | "${Strings.of(context)!.createdWith} ", 29 | style: Theme.of(context).textTheme.bodyText2, 30 | ), 31 | const Icon(Icons.favorite, color: Palette.red), 32 | Text( 33 | " ${Strings.of(context)!.and} ", 34 | style: Theme.of(context).textTheme.bodyText2, 35 | ), 36 | const FlutterLogo(), 37 | ], 38 | ), 39 | ], 40 | ), 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/core/localization/intl_en.arb: -------------------------------------------------------------------------------- 1 | { 2 | "chooseTheme": "Choose Theme", 3 | "chooseLanguage": "Choose Language", 4 | "underDevelopmentTitle": "This site is under development", 5 | "underDevelopmentDesc": "Until him complete the codes", 6 | "createdWith": "Created with", 7 | "and": "and", 8 | "sendEmail": "Send Email", 9 | "home": "Home", 10 | "profile": "Profile", 11 | "portfolio": "Portfolio", 12 | "services": "Services", 13 | "themeLight": "Theme Light", 14 | "themeDark": "Theme Dark", 15 | "themeSystem": "Theme System", 16 | "appDesc": "Lazycat Labs is a place to share about new tech and programming with a lazy way.", 17 | "blog": "Blog", 18 | "hello": "Hello", 19 | "profileTitle": "My name is Mudassir.", 20 | "profileDesc": " Currently working on ikhlas.com as Software Engineer II. I am specialized in Mobile Application Development with more than 5 years experience. Writing code for Android Native and Hybrid with Flutter Framework then implement mobile apps guidelines and realize UI/UX quality is one of the most important things in mobile apps development. That's why, I always try to deliver pixel perfect layouts tested on various devices.", 21 | "downloadCV": "Download CV", 22 | "buildTitle": "Build", 23 | "buildDesc": "Help you tou build an application\nfrom scratch with high quality code.", 24 | "fixTitle": "Fix", 25 | "fixDesc": "Fix bugs in your application\nand also improve the performance.", 26 | "continueTitle": "Continue", 27 | "continueDesc": "Continue your existing application project\nand improve the Application quality.", 28 | "portfolioDesc": "Latest project", 29 | "tags": "Tags:", 30 | "support": "Support Me", 31 | "socialMedia": "Follow Me", 32 | "seeMyBlog": "See my blog" 33 | } -------------------------------------------------------------------------------- /lib/utils/helper/constant.dart: -------------------------------------------------------------------------------- 1 | class Constants { 2 | Constants._(); 3 | 4 | static Constants get = Constants._(); 5 | 6 | String appName = "Lazycat Labs"; 7 | String english = "English"; 8 | String bahasa = "Bahasa"; 9 | String fontFamily = "VisueltPro"; 10 | 11 | String imagePlaceHolder = 12 | "https://cdn.dribbble.com/users/5478575/screenshots/12108011/media/17e913f849a16ea1f349b73afa04bbf9.jpg?compress=1&resize=400x300"; 13 | String linkedInUrl = "https://www.linkedin.com/in/mudassir-321462139/"; 14 | String upworkUrl = "https://www.upwork.com/freelancers/~01913209d41be922f1"; 15 | String githubSponsorUrl = "https://github.com/sponsors/Lzyct"; 16 | String githubUrl = "https://github.com/Lzyct"; 17 | 18 | String playStore = "Play Store"; 19 | String appStore = "App Store"; 20 | 21 | String github = "GitHub"; 22 | String linkedIn = "LinkedIn"; 23 | String upwork = "Upwork"; 24 | 25 | String githubSponsor = "GitHub Sponsor"; 26 | String kofi = "Ko-Fi"; 27 | String kofiUrl = "ko-fi.com/lzyct"; 28 | String buymecoffee = "Buy me a coffee"; 29 | String buymecoffeeUrl = "https://www.buymeacoffee.com/Lzyct"; 30 | String saweria = "Saweria"; 31 | String saweriaUrl = "https://saweria.co/Lzyct"; 32 | 33 | String youtubeUrl = 34 | "https://www.youtube.com/channel/UCzXKJlJHPIsQKhvuzHQ7ImA"; 35 | String instagramUrl = "https://www.instagram.com/lazycatlabs/"; 36 | String facebookUrl = "https://www.facebook.com/lazycatlabs/"; 37 | String tiktokUrl = "https://www.tiktok.com/@lazycatlabs"; 38 | String githubCommunityUrl = "https://github.com/lazycatlabs"; 39 | String blogUrl = "https://blog.lazycatlabs.com"; 40 | 41 | String playStoreUrl = 42 | "https://play.google.com/store/apps/dev?id=6313853259913767184"; 43 | } 44 | -------------------------------------------------------------------------------- /lib/core/localization/intl_id.arb: -------------------------------------------------------------------------------- 1 | { 2 | "chooseTheme": "Pilih Tema", 3 | "chooseLanguage": "Pilih Bahasa", 4 | "underDevelopmentTitle": "Situs ini dalam tahap pengembangan", 5 | "underDevelopmentDesc": "Sampai dia menyelesaikan code nya", 6 | "createdWith": "Dibuat menggunakan", 7 | "and": "dan", 8 | "sendEmail": "Kirim Email", 9 | "home": "Beranda", 10 | "profile": "Profil", 11 | "portfolio": "Portofolio", 12 | "services": "Layanan", 13 | "themeLight": "Tema Terang", 14 | "themeDark": "Tema Gelap", 15 | "themeSystem": "Tema Sistem", 16 | "appDesc": "Lazycat Labs adalah tempat untuk berbagi hal mengenai teknologi yang terbaru dan pemrograman dengan santai.", 17 | "blog": "Blog", 18 | "hello": "Halo", 19 | "profileTitle": "Nama saya Mudassir.", 20 | "profileDesc": " Saat ini saya bekerja di ikhlas.com sebagai Software Engineer II. Saya fokus dalam pengembangan aplikasi seluler dengan pengalaman lebih dari 5 tahun. Menulis kode untuk Android native maupun menggunakan Flutter, kemudian menerapkan pedoman dalam membuat aplikasi mobile dan membuat UI/UX berkualitas adalah salah satu hal terpenting dalam pengembangan aplikasi mobile. Itulah sebabnya, saya selalu mencoba mengimplementasikan tata letak piksel yang sempurna yang diuji pada berbagai perangkat.", 21 | "downloadCV": "Unduh CV", 22 | "buildTitle": "Membangun", 23 | "buildDesc": "Membantu Anda membangun aplikasi\ndari awal dengan kualitas kode yang baik.", 24 | "fixTitle": "Memperbaiki", 25 | "fixDesc": "Mencari dan memperbaiki masalah pada \naplikasi Anda dan juga meningkatkan performanya.", 26 | "continueTitle": "Melanjutkan", 27 | "continueDesc": "Melanjutkan project aplikasi Anda\ndan meningkatkan kualiatasnya.", 28 | "portfolioDesc": "Project terbaru", 29 | "tags": "Tag:", 30 | "support": "Dukung Saya", 31 | "socialMedia": "Ikuti Saya", 32 | "seeMyBlog": "Lihat blog saya" 33 | } 34 | -------------------------------------------------------------------------------- /lib/presentation/widgets/parent.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | ///********************************************* 4 | /// Created by ukietux on 24/08/20 with ♥ 5 | /// (>’_’)> email : ukie.tux@gmail.com 6 | /// github : https://www.github.com/Lzyct <(’_’<) 7 | ///********************************************* 8 | /// © 2020 | All Right Reserved 9 | class Parent extends StatefulWidget { 10 | final Widget? child; 11 | final PreferredSizeWidget? appBar; 12 | final bool avoidBottomInset; 13 | final Widget? floatingButton; 14 | final Widget? bottomNavigation; 15 | final Widget? drawer; 16 | final Widget? endDrawer; 17 | final Color? backgroundColor; 18 | final Key? scaffoldKey; 19 | final bool extendBodyBehindAppBar; 20 | 21 | const Parent({ 22 | super.key, 23 | this.child, 24 | this.appBar, 25 | this.avoidBottomInset = true, 26 | this.floatingButton, 27 | this.backgroundColor, 28 | this.bottomNavigation, 29 | this.drawer, 30 | this.scaffoldKey, 31 | this.endDrawer, 32 | this.extendBodyBehindAppBar = false, 33 | }); 34 | 35 | @override 36 | _ParentState createState() => _ParentState(); 37 | } 38 | 39 | class _ParentState extends State { 40 | @override 41 | Widget build(BuildContext context) { 42 | return GestureDetector( 43 | onTap: () => FocusManager.instance.primaryFocus?.unfocus(), 44 | child: Scaffold( 45 | key: widget.scaffoldKey, 46 | backgroundColor: widget.backgroundColor, 47 | resizeToAvoidBottomInset: widget.avoidBottomInset, 48 | extendBodyBehindAppBar: widget.extendBodyBehindAppBar, 49 | appBar: widget.appBar, 50 | body: widget.child, 51 | drawer: widget.drawer, 52 | endDrawer: widget.endDrawer, 53 | floatingActionButton: widget.floatingButton, 54 | bottomNavigationBar: widget.bottomNavigation, 55 | ), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/home/home_title.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | import 'package:lazycatlabs/utils/utils.dart'; 4 | 5 | class HomeTitle extends StatelessWidget { 6 | const HomeTitle({super.key, required this.animationController}); 7 | 8 | final AnimationController animationController; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return AnimatedWidgetShape( 13 | animationController: animationController, 14 | width: responsiveSize( 15 | context, 16 | Dimens.space130 + Dimens.space12, 17 | Dimens.space200 + Dimens.space12, 18 | tablet: Dimens.space150 + Dimens.space12, 19 | ), 20 | height: responsiveSize( 21 | context, 22 | Dimens.space130 + Dimens.space12, 23 | Dimens.space200 + Dimens.space12, 24 | tablet: Dimens.space150 + Dimens.space12, 25 | ), 26 | boxShape: BoxShape.circle, 27 | child: Stack( 28 | children: [ 29 | CircleAvatar( 30 | radius: Dimens.space24, 31 | backgroundColor: Theme.of(context).cardColor, 32 | ), 33 | CircleAvatar( 34 | radius: responsiveSize( 35 | context, 36 | Dimens.space64, 37 | Dimens.space150, 38 | tablet: Dimens.space72, 39 | ) + 40 | Dimens.space12, 41 | backgroundColor: Theme.of(context).cardColor, 42 | child: CircleAvatar( 43 | backgroundImage: AssetImage(Images.icAvatar), 44 | radius: responsiveSize( 45 | context, 46 | Dimens.space58, 47 | Dimens.space92, 48 | tablet: Dimens.space72, 49 | ), 50 | ), 51 | ), 52 | ], 53 | ), 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/profile/profile_title.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | import 'package:lazycatlabs/utils/utils.dart'; 4 | 5 | class ProfileTitle extends StatelessWidget { 6 | const ProfileTitle({super.key, required this.animationController}); 7 | 8 | final AnimationController animationController; 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return AnimatedWidgetShape( 13 | animationController: animationController, 14 | width: responsiveSize( 15 | context, 16 | Dimens.space130 + Dimens.space12, 17 | Dimens.space200 + Dimens.space12, 18 | tablet: Dimens.space150 + Dimens.space12, 19 | ), 20 | height: responsiveSize( 21 | context, 22 | Dimens.space130 + Dimens.space12, 23 | Dimens.space200 + Dimens.space12, 24 | tablet: Dimens.space150 + Dimens.space12, 25 | ), 26 | boxShape: BoxShape.circle, 27 | child: Stack( 28 | children: [ 29 | CircleAvatar( 30 | radius: Dimens.space24, 31 | backgroundColor: Theme.of(context).cardColor, 32 | ), 33 | CircleAvatar( 34 | radius: responsiveSize( 35 | context, 36 | Dimens.space64, 37 | Dimens.space150, 38 | tablet: Dimens.space72, 39 | ) + 40 | Dimens.space12, 41 | backgroundColor: Theme.of(context).cardColor, 42 | child: CircleAvatar( 43 | backgroundImage: AssetImage(Images.icProfile), 44 | radius: responsiveSize( 45 | context, 46 | Dimens.space58, 47 | Dimens.space92, 48 | tablet: Dimens.space72, 49 | ), 50 | ), 51 | ), 52 | ], 53 | ), 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/services/services_title.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/core/core.dart'; 3 | import 'package:lazycatlabs/presentation/presentation.dart'; 4 | import 'package:lazycatlabs/utils/utils.dart'; 5 | 6 | class ServicesTitle extends StatelessWidget { 7 | const ServicesTitle({super.key, required this.animationController}); 8 | 9 | final AnimationController animationController; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return AnimatedWidgetShape( 14 | animationController: animationController, 15 | width: responsiveSize( 16 | context, 17 | context.widthInPercent(44), 18 | context.widthInPercent(28), 19 | tablet: Dimens.space220, 20 | ), 21 | height: responsiveSize( 22 | context, 23 | Dimens.space100, 24 | Dimens.space200, 25 | tablet: Dimens.space120, 26 | ), 27 | child: Stack( 28 | alignment: Alignment.center, 29 | children: [ 30 | Positioned( 31 | right: 0, 32 | child: Icon( 33 | Icons.circle, 34 | color: Theme.of(context).cardColor, 35 | size: responsiveSize(context, Dimens.space72, Dimens.space150), 36 | ), 37 | ), 38 | Positioned( 39 | left: 0, 40 | bottom: responsiveSize( 41 | context, 42 | Dimens.space30, 43 | Dimens.space48, 44 | ), 45 | child: Text( 46 | Strings.of(context)!.services, 47 | style: Theme.of(context).textTheme.headline1?.copyWith( 48 | fontSize: responsiveSize( 49 | context, 50 | Dimens.space36, 51 | Dimens.h1, 52 | tablet: Dimens.h3, 53 | ), 54 | ), 55 | ), 56 | ), 57 | ], 58 | ), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/presentation/widgets/animated_mouse.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | 4 | class AnimatedMouse extends StatefulWidget { 5 | const AnimatedMouse({super.key}); 6 | 7 | @override 8 | State createState() => _AnimatedMouseState(); 9 | } 10 | 11 | class _AnimatedMouseState extends State 12 | with SingleTickerProviderStateMixin { 13 | late final AnimationController _animationController = AnimationController( 14 | duration: const Duration(milliseconds: 800), 15 | vsync: this, 16 | )..repeat(reverse: true); 17 | 18 | late final Animation _animatedAlign = 19 | Tween(begin: Alignment.topCenter, end: const Alignment(0, 0.45)) 20 | .animate(_animationController); 21 | 22 | @override 23 | void dispose() { 24 | super.dispose(); 25 | _animationController.dispose(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return AnimatedBuilder( 31 | animation: _animationController, 32 | builder: (context, _) { 33 | return AnimatedContainer( 34 | duration: const Duration(milliseconds: 300), 35 | width: Dimens.space30, 36 | height: Dimens.space36 * 1.3, 37 | alignment: _animatedAlign.value, 38 | decoration: BoxDecoration( 39 | borderRadius: BorderRadius.circular(Dimens.space30), 40 | border: Border.all( 41 | color: Palette.hint, 42 | width: Dimens.space3, 43 | ), 44 | ), 45 | child: AnimatedOpacity( 46 | duration: const Duration(milliseconds: 300), 47 | opacity: 48 | _animationController.status == AnimationStatus.forward ? 1 : 0, 49 | child: Container( 50 | width: Dimens.space4, 51 | height: Dimens.space12, 52 | decoration: BoxDecoration( 53 | color: Palette.hint, 54 | borderRadius: BorderRadius.circular(Dimens.space8), 55 | ), 56 | ), 57 | ), 58 | ); 59 | }, 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | Lazycat Labs 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /lib/presentation/resources/dimens.dart: -------------------------------------------------------------------------------- 1 | class Dimens { 2 | Dimens._(); 3 | 4 | static double h1 = 96; 5 | static double h2 = 60; 6 | static double h3 = 48; 7 | static double h4 = 34; 8 | static double h5 = 24; 9 | static double h6 = 20; 10 | static double body1 = 16; 11 | static double body2 = 14; 12 | static double subtitle1 = 16; 13 | static double subtitle2 = 14; 14 | static double button = 14; 15 | static double caption = 12; 16 | static double overline = 10; 17 | 18 | static double zero = 0; 19 | static double space1 = 1; 20 | static double space2 = 2; 21 | static double space3 = 3; 22 | static double space4 = 4; 23 | static double space6 = 6; 24 | static double space8 = 8; 25 | static double space10 = 10; 26 | static double space12 = 12; 27 | static double space16 = 16; 28 | static double space17 = 17; 29 | static double space18 = 18; 30 | static double space20 = 20; 31 | static double space24 = 24; 32 | static double space30 = 30; 33 | static double space36 = 36; 34 | static double space42 = 42; 35 | static double space46 = 46; 36 | static double space48 = 48; 37 | static double space50 = 50; 38 | static double space58 = 58; 39 | static double space64 = 64; 40 | static double space72 = 72; 41 | static double space92 = 92; 42 | static double space100 = 100; 43 | static double space120 = 120; 44 | static double space130 = 130; 45 | static double space150 = 150; 46 | static double space180 = 180; 47 | static double space200 = 200; 48 | static double space220 = 220; 49 | static double space250 = 250; 50 | static double space280 = 280; 51 | static double space300 = 300; 52 | static double space400 = 400; 53 | 54 | static double selectedIndicatorW = 43; 55 | static double selectedIndicatorSmallW = 28; 56 | static double heightAppbarHome = 65; 57 | static double tab = 38; 58 | static double menu = 200; 59 | static double iconDropdown = 50; 60 | static double menuContainer = 350; 61 | static double carousel = 167; 62 | 63 | static double header = 160; 64 | static double minLabel = 116; 65 | static double bottomBar = 80; 66 | static double buttonH = 50; 67 | static double buttonWidth = 110; 68 | 69 | static const double cornerRadius = 15; 70 | static const double cornerButton = 80; 71 | static const double widthToast = 250; 72 | } 73 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/home/home_description.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/core/core.dart'; 3 | import 'package:lazycatlabs/presentation/presentation.dart'; 4 | import 'package:lazycatlabs/utils/utils.dart'; 5 | import 'package:url_launcher/url_launcher_string.dart'; 6 | 7 | class HomeDescription extends StatelessWidget { 8 | const HomeDescription({ 9 | super.key, 10 | required this.animationController, 11 | }); 12 | 13 | final AnimationController animationController; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Padding( 18 | padding: EdgeInsets.all(Dimens.space24), 19 | child: Column( 20 | crossAxisAlignment: CrossAxisAlignment.start, 21 | mainAxisSize: MainAxisSize.min, 22 | children: [ 23 | AnimatedTextBox( 24 | animationController: animationController, 25 | text: "${Constants.get.appName}.", 26 | maxLines: 3, 27 | textStyle: Theme.of(context).textTheme.headline1!.copyWith( 28 | fontSize: responsiveSize( 29 | context, 30 | Dimens.space36, 31 | Dimens.h1, 32 | tablet: Dimens.h2, 33 | ), 34 | ), 35 | ), 36 | AnimatedTextBox( 37 | animationController: animationController, 38 | text: Strings.of(context)!.appDesc, 39 | heightFactor: responsiveSize(context, 2, 1), 40 | maxLines: responsiveSize(context, 2, 1).toInt(), 41 | textStyle: Theme.of(context).textTheme.bodyText1!.copyWith( 42 | fontSize: responsiveSize( 43 | context, 44 | Dimens.body2, 45 | Dimens.space17, 46 | ), 47 | ), 48 | ), 49 | SpacerV(value: Dimens.space24), 50 | AnimatedWidgetShape( 51 | animationController: animationController, 52 | width: Dimens.space150, 53 | height: Dimens.buttonH, 54 | child: Button( 55 | targetWidth: Dimens.space150, 56 | title: Strings.of(context)!.seeMyBlog, 57 | onPressed: () { 58 | launchUrlString(Constants.get.blogUrl); 59 | }, 60 | ), 61 | ), 62 | ], 63 | ), 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/data/datasources/local/pref_manager.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:shared_preferences/shared_preferences.dart'; 4 | 5 | enum ActiveTheme { 6 | light( 7 | ThemeMode.light, 8 | Icons.wb_sunny, 9 | ), 10 | dark(ThemeMode.dark, Icons.brightness_2), 11 | system(ThemeMode.system, Icons.brightness_auto_rounded); 12 | 13 | final ThemeMode mode; 14 | final IconData icon; 15 | 16 | const ActiveTheme(this.mode, this.icon); 17 | } 18 | 19 | class PrefManager { 20 | String kIsLogin = "isLogin"; 21 | String kToken = "token"; 22 | String kText = "text"; 23 | String kColor = "color"; 24 | String kIcon = "icon"; 25 | String kUser = "user"; 26 | String kFCM = "fcm"; 27 | String kLanguage = "language"; 28 | String kLocale = "locale"; 29 | String kTheme = "theme"; 30 | 31 | /// Light, Dark ,System 32 | 33 | SharedPreferences preferences; 34 | 35 | PrefManager(this.preferences); 36 | 37 | //for Bloc.Bloc.login 38 | set isLogin(bool value) => preferences.setBool(kIsLogin, value); 39 | 40 | bool get isLogin => preferences.getBool(kIsLogin) ?? false; 41 | 42 | set token(String? value) => preferences.setString(kToken, value ?? ""); 43 | 44 | String? get token => preferences.getString(kToken); 45 | 46 | set fcmToken(String? value) => preferences.setString(kFCM, value ?? ""); 47 | 48 | String? get fcmToken => preferences.getString(kFCM); 49 | 50 | set user(String? value) => preferences.setString(kUser, value ?? ""); 51 | 52 | String? get user => preferences.getString(kUser); 53 | 54 | set text(String? value) => preferences.setString(kText, value ?? ""); 55 | 56 | String get text => preferences.getString(kText) ?? ""; 57 | 58 | set color(String? value) => preferences.setString(kColor, value ?? ""); 59 | 60 | String? get color => preferences.getString(kColor); 61 | 62 | set icon(String? value) => preferences.setString(kIcon, value ?? ""); 63 | 64 | String? get icon => preferences.getString(kIcon); 65 | 66 | /// Default locale set to English 67 | set locale(String? value) => preferences.setString(kLocale, value ?? "en"); 68 | 69 | String get locale => preferences.getString(kLocale) ?? "en"; 70 | 71 | /// Default locale set to English 72 | set theme(String? value) => 73 | preferences.setString(kTheme, value ?? describeEnum(ActiveTheme.system)); 74 | 75 | String get theme => 76 | preferences.getString(kTheme) ?? describeEnum(ActiveTheme.system); 77 | 78 | void logout() => preferences.clear(); 79 | } 80 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/portfolio/portfolio_title.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/core/core.dart'; 3 | import 'package:lazycatlabs/presentation/presentation.dart'; 4 | import 'package:lazycatlabs/utils/utils.dart'; 5 | 6 | class PortfolioTitle extends StatelessWidget { 7 | const PortfolioTitle({super.key, required this.animationController}); 8 | 9 | final AnimationController animationController; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return AnimatedWidgetShape( 14 | animationController: animationController, 15 | width: responsiveSize( 16 | context, 17 | context.widthInPercent(45), 18 | context.widthInPercent(32), 19 | tablet: Dimens.space250, 20 | ), 21 | height: responsiveSize( 22 | context, 23 | Dimens.space100, 24 | Dimens.space200, 25 | tablet: Dimens.space120, 26 | ), 27 | child: Stack( 28 | alignment: Alignment.center, 29 | children: [ 30 | Positioned( 31 | right: 0, 32 | child: Icon( 33 | Icons.circle, 34 | color: Theme.of(context).cardColor, 35 | size: responsiveSize(context, Dimens.space72, Dimens.space150), 36 | ), 37 | ), 38 | Positioned( 39 | left: 0, 40 | bottom: responsiveSize( 41 | context, 42 | Dimens.space20, 43 | Dimens.space30, 44 | ), 45 | child: Column( 46 | crossAxisAlignment: CrossAxisAlignment.end, 47 | children: [ 48 | Text( 49 | Strings.of(context)!.portfolio, 50 | style: Theme.of(context).textTheme.headline1?.copyWith( 51 | fontSize: responsiveSize( 52 | context, 53 | Dimens.space36, 54 | Dimens.h1, 55 | tablet: Dimens.h3, 56 | ), 57 | ), 58 | ), 59 | Text( 60 | Strings.of(context)!.portfolioDesc, 61 | style: Theme.of(context).textTheme.headline6?.copyWith( 62 | fontSize: 63 | responsiveSize(context, Dimens.body1, Dimens.h6), 64 | ), 65 | ) 66 | ], 67 | ), 68 | ), 69 | ], 70 | ), 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/data/datasources/local/portfolio_response.dart: -------------------------------------------------------------------------------- 1 | class PortfolioResponse { 2 | PortfolioResponse({ 3 | this.data, 4 | }); 5 | 6 | PortfolioResponse.fromJson(dynamic json) { 7 | if (json['data'] != null) { 8 | data = []; 9 | json['data'].forEach((v) { 10 | data?.add(Data.fromJson(v)); 11 | }); 12 | } 13 | } 14 | 15 | List? data; 16 | 17 | PortfolioResponse copyWith({ 18 | List? data, 19 | }) => 20 | PortfolioResponse( 21 | data: data ?? this.data, 22 | ); 23 | 24 | Map toJson() { 25 | final map = {}; 26 | if (data != null) { 27 | map['data'] = data?.map((v) => v.toJson()).toList(); 28 | } 29 | return map; 30 | } 31 | } 32 | 33 | class Data { 34 | Data({ 35 | this.title, 36 | this.descriptions, 37 | this.images, 38 | this.playStore, 39 | this.appStore, 40 | this.tag, 41 | this.onClick = false, 42 | this.onHover = false, 43 | this.activeIndex = 0, 44 | }); 45 | 46 | Data.fromJson(dynamic json) { 47 | title = json['title'] as String?; 48 | descriptions = json['descriptions'] as String?; 49 | images = json['images'] != null 50 | ? json['images'].cast() as List? 51 | : []; 52 | playStore = json['playStore'] as String?; 53 | appStore = json['appStore'] as String?; 54 | tag = 55 | json['tag'] != null ? json['tag'].cast() as List? : []; 56 | } 57 | 58 | String? title; 59 | String? descriptions; 60 | List? images; 61 | String? playStore; 62 | String? appStore; 63 | List? tag; 64 | bool onHover = false; 65 | bool onClick = false; 66 | int activeIndex = 0; 67 | 68 | Data copyWith({ 69 | String? title, 70 | String? descriptions, 71 | List? images, 72 | String? playStore, 73 | String? appStore, 74 | List? tag, 75 | }) => 76 | Data( 77 | title: title ?? this.title, 78 | descriptions: descriptions ?? this.descriptions, 79 | images: images ?? this.images, 80 | playStore: playStore ?? this.playStore, 81 | appStore: appStore ?? this.appStore, 82 | tag: tag ?? this.tag, 83 | ); 84 | 85 | Map toJson() { 86 | final map = {}; 87 | map['title'] = title; 88 | map['descriptions'] = descriptions; 89 | map['images'] = images; 90 | map['playStore'] = playStore; 91 | map['appStore'] = appStore; 92 | map['tag'] = tag; 93 | return map; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/profile/profile_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/data/data.dart'; 3 | import 'package:lazycatlabs/presentation/presentation.dart'; 4 | import 'package:lazycatlabs/utils/utils.dart'; 5 | import 'package:url_launcher/url_launcher_string.dart'; 6 | 7 | class ProfileButton extends StatelessWidget { 8 | const ProfileButton({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | final List buttons = [ 13 | DataHelper( 14 | title: Constants.get.linkedIn, 15 | iconPath: Images.icLinkedIn, 16 | iconColor: Palette.linkedIn, 17 | url: Constants.get.linkedInUrl, 18 | ), 19 | DataHelper( 20 | title: Constants.get.upwork, 21 | iconPath: Images.icUpwork, 22 | url: Constants.get.upworkUrl, 23 | ), 24 | DataHelper( 25 | title: Constants.get.github, 26 | iconPath: Images.icGithub, 27 | iconColor: Theme.of(context).textTheme.bodyText1?.color, 28 | url: Constants.get.githubUrl, 29 | ), 30 | ]; 31 | 32 | return Wrap( 33 | runSpacing: Dimens.space16, 34 | spacing: Dimens.space16, 35 | children: buttons 36 | .asMap() 37 | .entries 38 | .map( 39 | (element) => Wrap( 40 | children: [ 41 | AnimatedTextStrikethrough( 42 | text: element.value.title ?? "", 43 | textStyle: Theme.of(context) 44 | .textTheme 45 | .bodyText1! 46 | .copyWith(decoration: TextDecoration.underline), 47 | textStyleHover: Theme.of(context) 48 | .textTheme 49 | .bodyText1! 50 | .copyWith(fontWeight: FontWeight.w500), 51 | duration: const Duration(milliseconds: 400), 52 | onTap: () { 53 | launchUrlString(element.value.url!); 54 | }, 55 | ), 56 | if (element.key < buttons.length - 1) ...{ 57 | SpacerH(value: Dimens.space16), 58 | Text( 59 | "/", 60 | style: Theme.of(context) 61 | .textTheme 62 | .bodyText1 63 | ?.copyWith(fontWeight: FontWeight.normal), 64 | ), 65 | } 66 | ], 67 | ), 68 | ) 69 | .toList(), 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/presentation/widgets/animated_box_slider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | const double _hiddenFactor = 3; 4 | 5 | class AnimatedBoxSlider extends AnimatedWidget { 6 | const AnimatedBoxSlider({ 7 | super.key, 8 | required this.controller, 9 | required this.width, 10 | required this.height, 11 | this.visibleBoxAnimation, 12 | this.invisibleBoxAnimation, 13 | this.visibleBoxCurve = Curves.fastOutSlowIn, 14 | this.invisibleBoxCurve = Curves.fastOutSlowIn, 15 | }) : super(listenable: controller); 16 | 17 | final AnimationController controller; 18 | final double width; 19 | final double height; 20 | final Curve visibleBoxCurve; 21 | final Curve invisibleBoxCurve; 22 | final Animation? visibleBoxAnimation; 23 | final Animation? invisibleBoxAnimation; 24 | 25 | Animation get _visibleAnimation => 26 | visibleBoxAnimation ?? 27 | Tween(begin: 0, end: width - (_hiddenFactor * 2)).animate( 28 | CurvedAnimation( 29 | parent: controller, 30 | curve: Interval(0, 0.5, curve: visibleBoxCurve), 31 | ), 32 | ); 33 | 34 | Animation get _invisibleAnimation => 35 | Tween(begin: 0, end: width).animate( 36 | CurvedAnimation( 37 | parent: controller, 38 | curve: Interval(0.5, 1.0, curve: invisibleBoxCurve), 39 | ), 40 | ); 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | return SizedBox( 45 | width: width, 46 | height: height, 47 | child: Stack( 48 | children: [ 49 | Positioned( 50 | top: _hiddenFactor, 51 | left: _hiddenFactor, 52 | child: Container( 53 | width: (_visibleAnimation.value > (_hiddenFactor * 2)) 54 | ? _visibleAnimation.value - (_hiddenFactor * 2) 55 | : _visibleAnimation.value, 56 | height: height - (_hiddenFactor * 2), 57 | color: controller.isCompleted 58 | ? Colors.transparent 59 | : Theme.of(context).textTheme.bodyText1?.color, 60 | ), 61 | ), 62 | Positioned( 63 | top: 0, 64 | child: Container( 65 | width: controller.isCompleted ? 0 : _invisibleAnimation.value, 66 | height: controller.isCompleted ? 0 : height, 67 | color: controller.isCompleted 68 | ? Colors.transparent 69 | : Theme.of(context).scaffoldBackgroundColor, 70 | ), 71 | ), 72 | ], 73 | ), 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/main_menu.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/data/datasources/datasources.dart'; 3 | import 'package:lazycatlabs/presentation/presentation.dart'; 4 | import 'package:lazycatlabs/utils/utils.dart'; 5 | 6 | class MainMenu extends StatefulWidget { 7 | const MainMenu({ 8 | super.key, 9 | required this.listMenu, 10 | required this.scrollController, 11 | required this.duration, 12 | }); 13 | 14 | final List listMenu; 15 | final ScrollController scrollController; 16 | final int duration; 17 | 18 | @override 19 | State createState() => _MainMenuState(); 20 | } 21 | 22 | class _MainMenuState extends State { 23 | @override 24 | Widget build(BuildContext context) { 25 | return Row( 26 | mainAxisAlignment: MainAxisAlignment.end, 27 | children: widget.listMenu.asMap().entries.map((e) { 28 | return Padding( 29 | padding: EdgeInsets.symmetric(horizontal: Dimens.space10), 30 | child: Row( 31 | children: [ 32 | AnimatedOpacity( 33 | opacity: e.value.isSelected ? 1 : 0, 34 | duration: Duration(milliseconds: widget.duration), 35 | child: Row( 36 | children: [ 37 | CircleAvatar( 38 | backgroundColor: Palette.primary, 39 | radius: Dimens.space2, 40 | ), 41 | SpacerH(value: Dimens.space2), 42 | ], 43 | ), 44 | ), 45 | AnimatedTextStrikethrough( 46 | text: e.value.title ?? "", 47 | textStyle: Theme.of(context).textTheme.bodyText1!, 48 | textStyleHover: Theme.of(context) 49 | .textTheme 50 | .bodyText1! 51 | .copyWith(fontWeight: FontWeight.w500), 52 | duration: Duration(milliseconds: widget.duration), 53 | onTap: () { 54 | setState(() { 55 | for (final item in widget.listMenu) { 56 | item.isSelected = false; 57 | } 58 | e.value.isSelected = true; 59 | 60 | widget.scrollController.animateTo( 61 | e.key * (context.heightInPercent(100)), 62 | duration: Duration(milliseconds: widget.duration), 63 | curve: Curves.linear, 64 | ); 65 | }); 66 | }, 67 | ) 68 | ], 69 | ), 70 | ); 71 | }).toList(), 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/presentation/widgets/scroll_indicator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ScrollIndicator extends StatefulWidget { 4 | final ScrollController scrollController; 5 | final PageController pageController; 6 | final double width; 7 | final double height; 8 | final double indicatorWidth; 9 | final Decoration decoration; 10 | final Decoration indicatorDecoration; 11 | final AlignmentGeometry alignment; 12 | 13 | const ScrollIndicator({ 14 | required this.scrollController, 15 | required this.pageController, 16 | this.width = 100, 17 | this.height = 10, 18 | this.indicatorWidth = 20, 19 | this.decoration = const BoxDecoration(color: Colors.black26), 20 | this.indicatorDecoration = const BoxDecoration(color: Colors.black), 21 | this.alignment = Alignment.center, 22 | }); 23 | 24 | @override 25 | _ScrollIndicatorState createState() => _ScrollIndicatorState(); 26 | } 27 | 28 | class _ScrollIndicatorState extends State { 29 | double currentPixels = 0.0; 30 | double mainContainer = 0.0; 31 | double move = 0.0; 32 | 33 | @override 34 | void initState() { 35 | widget.scrollController.addListener(() { 36 | _scrollListener(); 37 | }); 38 | widget.pageController.addListener(() { 39 | _pageListener(); 40 | }); 41 | super.initState(); 42 | } 43 | 44 | void _scrollListener() { 45 | setState(() { 46 | currentPixels = widget.scrollController.position.pixels; 47 | mainContainer = 48 | widget.scrollController.position.maxScrollExtent / widget.width; 49 | move = currentPixels / mainContainer; 50 | }); 51 | } 52 | 53 | void _pageListener() { 54 | setState(() { 55 | currentPixels = widget.pageController.position.pixels; 56 | mainContainer = 57 | widget.pageController.position.maxScrollExtent / widget.width; 58 | move = currentPixels / mainContainer; 59 | }); 60 | } 61 | 62 | @override 63 | Widget build(BuildContext context) { 64 | return Align( 65 | alignment: widget.alignment, 66 | child: Container( 67 | height: widget.height, 68 | width: widget.width + widget.indicatorWidth, 69 | decoration: widget.decoration, 70 | child: Stack( 71 | fit: StackFit.expand, 72 | children: [ 73 | AnimatedPositioned( 74 | duration: const Duration(milliseconds: 300), 75 | left: move, 76 | child: Container( 77 | height: widget.height, 78 | width: widget.indicatorWidth, 79 | decoration: widget.indicatorDecoration, 80 | ), 81 | ), 82 | ], 83 | ), 84 | ), 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /lib/presentation/resources/palette.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | // 100% — FF ## 50% — 80 4 | // 99% — FC ## 49% — 7D 5 | // 98% — FA ## 48% — 7A 6 | // 97% — F7 ## 47% — 78 7 | // 96% — F5 ## 46% — 75 8 | // 95% — F2 ## 45% — 73 9 | // 94% — F0 ## 44% — 70 10 | // 93% — ED ## 43% — 6E 11 | // 92% — EB ## 42% — 6B 12 | // 91% — E8 ## 41% — 69 13 | // 90% — E6 ## 40% — 66 14 | // 89% — E3 ## 39% — 63 15 | // 88% — E0 ## 38% — 61 16 | // 87% — DE ## 37% — 5E 17 | // 86% — DB ## 36% — 5C 18 | // 85% — D9 ## 35% — 59 19 | // 84% — D6 ## 34% — 57 20 | // 83% — D4 ## 33% — 54 21 | // 82% — D1 ## 32% — 52 22 | // 81% — CF ## 31% — 4F 23 | // 80% — CC ## 30% — 4D 24 | // 79% — C9 ## 29% — 4A 25 | // 78% — C7 ## 28% — 47 26 | // 77% — C4 ## 27% — 45 27 | // 76% — C2 ## 26% — 42 28 | // 75% — BF ## 25% — 40 29 | // 74% — BD ## 24% — 3D 30 | // 73% — BA ## 23% — 3B 31 | // 72% — B8 ## 22% — 38 32 | // 71% — B5 ## 21% — 36 33 | // 70% — B3 ## 20% — 33 34 | // 69% — B0 ## 19% — 30 35 | // 68% — AD ## 18% — 2E 36 | // 67% — AB ## 17% — 2B 37 | // 66% — A8 ## 16% — 29 38 | // 65% — A6 ## 15% — 26 39 | // 64% — A3 ## 14% — 24 40 | // 63% — A1 ## 13% — 21 41 | // 62% — 9E ## 12% — 1F 42 | // 61% — 9C ## 11% — 1C 43 | // 60% — 99 ## 10% — 1A 44 | // 59% — 96 ## 9% — 17 45 | // 58% — 94 ## 8% — 14 46 | // 57% — 91 ## 7% — 12 47 | // 56% — 8F ## 6% — 0F 48 | // 55% — 8C ## 5% — 0D 49 | // 54% — 8A ## 4% — 0A 50 | // 53% — 87 ## 3% — 08 51 | // 52% — 85 ## 2% — 05 52 | // 51% — 82 ## 1% — 03 53 | 54 | class Palette { 55 | Palette._(); 56 | 57 | static const Color primary = Color(0xffE18925); 58 | static const Color primaryLight = Color(0xffF7B553); 59 | static const Color darkBackground = Color(0xff18191A); 60 | static const Color darkCard = Color(0xff242526); 61 | static const Color accent = primary; 62 | static const Color white = Color(0xffffffff); 63 | static const Color offWhite = Color(0xfff3f3f3); 64 | static const Color background = white; 65 | static const Color text = Color(0xff303030); 66 | static const Color textAlt = Color(0xff3D3D3D); 67 | static const Color hint = Color(0xff7E7E7E); 68 | static const Color disable = Color(0xffC4C4C4); 69 | static const Color red = Color(0xffED6464); 70 | static const Color divider = Color(0xffE0E0E0); 71 | static const Color yellow = Color(0xffF7BD00); 72 | static const Color green = Color(0xff27AE60); 73 | static const Color black10 = Color(0x1A000000); 74 | static const Color black15 = Color(0x26000000); 75 | static const Color black20 = Color(0x33000000); 76 | static const Color black25 = Color(0x40000000); 77 | static const Color black = Color(0xFF000000); 78 | static const Color linkedIn = Color(0xFF0e76a8); 79 | static const Color facebook = Color(0xff3b5998); 80 | static const Color youtube = Color(0xffc4302b); 81 | } 82 | -------------------------------------------------------------------------------- /lib/presentation/widgets/animated_widget_slider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | const double _hiddenFactor = 2; 4 | 5 | class AnimatedWidgetSlider extends AnimatedWidget { 6 | const AnimatedWidgetSlider({ 7 | super.key, 8 | required this.controller, 9 | required this.width, 10 | required this.height, 11 | this.visibleBoxAnimation, 12 | this.invisibleBoxAnimation, 13 | this.visibleBoxCurve = Curves.fastOutSlowIn, 14 | this.invisibleBoxCurve = Curves.fastOutSlowIn, 15 | this.boxShape = BoxShape.rectangle, 16 | }) : super(listenable: controller); 17 | 18 | final AnimationController controller; 19 | final double width; 20 | final double height; 21 | final Curve visibleBoxCurve; 22 | final Curve invisibleBoxCurve; 23 | final Animation? visibleBoxAnimation; 24 | final Animation? invisibleBoxAnimation; 25 | final BoxShape boxShape; 26 | 27 | Animation get _visibleAnimation => 28 | visibleBoxAnimation ?? 29 | Tween(begin: 0, end: width - (_hiddenFactor * 2)).animate( 30 | CurvedAnimation( 31 | parent: controller, 32 | curve: Interval(0, 0.5, curve: visibleBoxCurve), 33 | ), 34 | ); 35 | 36 | Animation get _invisibleAnimation => 37 | Tween(begin: 0, end: width).animate( 38 | CurvedAnimation( 39 | parent: controller, 40 | curve: Interval(0.5, 1.0, curve: invisibleBoxCurve), 41 | ), 42 | ); 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return SizedBox( 47 | width: width, 48 | height: height, 49 | child: Stack( 50 | children: [ 51 | Positioned( 52 | top: _hiddenFactor, 53 | left: _hiddenFactor, 54 | child: Container( 55 | width: (_visibleAnimation.value > (_hiddenFactor * 2)) 56 | ? _visibleAnimation.value - (_hiddenFactor * 2) 57 | : _visibleAnimation.value, 58 | height: height - (_hiddenFactor * 2), 59 | decoration: BoxDecoration( 60 | shape: boxShape, 61 | color: controller.isCompleted 62 | ? Colors.transparent 63 | : Theme.of(context).textTheme.bodyText1?.color, 64 | ), 65 | ), 66 | ), 67 | Positioned( 68 | top: 0, 69 | child: Container( 70 | width: _invisibleAnimation.value, 71 | height: height, 72 | decoration: BoxDecoration( 73 | shape: boxShape, 74 | color: controller.isCompleted 75 | ? Colors.transparent 76 | : Theme.of(context).scaffoldBackgroundColor, 77 | ), 78 | ), 79 | ), 80 | ], 81 | ), 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /assets/images/ic_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/profile/profile_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | import 'package:lazycatlabs/utils/utils.dart'; 4 | import 'package:visibility_detector/visibility_detector.dart'; 5 | 6 | class ProfileSection extends StatefulWidget { 7 | const ProfileSection({ 8 | super.key, 9 | required this.isVisible, 10 | }); 11 | 12 | final Function(bool) isVisible; 13 | 14 | @override 15 | State createState() => _ProfileSectionState(); 16 | } 17 | 18 | class _ProfileSectionState extends State 19 | with TickerProviderStateMixin { 20 | bool? _temp; 21 | bool _isVisible = true; 22 | bool _isFirst = true; 23 | final int _visibilityPercent = 50; 24 | 25 | late final AnimationController _animationController = AnimationController( 26 | vsync: this, 27 | duration: durationLong, 28 | ); 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return SliverToBoxAdapter( 33 | child: VisibilityDetector( 34 | key: const Key("profile"), 35 | onVisibilityChanged: (VisibilityInfo info) { 36 | final visiblePercentage = info.visibleFraction * 100; 37 | 38 | if (_temp == null) { 39 | _temp = visiblePercentage > _visibilityPercent; 40 | widget.isVisible(_temp ?? true); 41 | setState(() { 42 | _isVisible = _temp ?? true; 43 | }); 44 | } else { 45 | if (_temp != visiblePercentage.isVisible()) { 46 | _temp = visiblePercentage > _visibilityPercent; 47 | widget.isVisible(_temp ?? true); 48 | setState(() { 49 | _isVisible = _temp ?? true; 50 | }); 51 | } 52 | } 53 | 54 | if (_isVisible && _isFirst) { 55 | _animationController.forward(); 56 | _isFirst = false; 57 | } 58 | }, 59 | child: ConstrainedBox( 60 | constraints: BoxConstraints( 61 | minWidth: context.widthInPercent(100), 62 | minHeight: context.heightInPercent(100), 63 | ), 64 | child: Column( 65 | mainAxisAlignment: MainAxisAlignment.center, 66 | crossAxisAlignment: CrossAxisAlignment.start, 67 | mainAxisSize: MainAxisSize.min, 68 | children: [ 69 | Center( 70 | child: ProfileTitle(animationController: _animationController), 71 | ), 72 | SpacerV( 73 | value: responsiveSize( 74 | context, 75 | Dimens.space16, 76 | Dimens.space50, 77 | tablet: Dimens.space30, 78 | ), 79 | ), 80 | ProfileDescription(animationController: _animationController), 81 | SpacerV(value: Dimens.space100), 82 | ], 83 | ), 84 | ), 85 | ), 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/portfolio/portfolio_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | import 'package:lazycatlabs/utils/utils.dart'; 4 | import 'package:visibility_detector/visibility_detector.dart'; 5 | 6 | class PortfolioSection extends StatefulWidget { 7 | const PortfolioSection({ 8 | super.key, 9 | required this.isVisible, 10 | }); 11 | 12 | final Function(bool) isVisible; 13 | 14 | @override 15 | State createState() => _PortfolioSectionState(); 16 | } 17 | 18 | class _PortfolioSectionState extends State 19 | with TickerProviderStateMixin { 20 | bool? _temp; 21 | bool _isVisible = true; 22 | bool _isFirst = true; 23 | final int _visibilityPercent = 50; 24 | late final AnimationController _animationController = AnimationController( 25 | vsync: this, 26 | duration: durationLong, 27 | ); 28 | 29 | @override 30 | Widget build(BuildContext context) { 31 | return SliverToBoxAdapter( 32 | child: VisibilityDetector( 33 | key: const Key("portfolio"), 34 | onVisibilityChanged: (VisibilityInfo info) { 35 | final visiblePercentage = info.visibleFraction * 100; 36 | 37 | if (_temp == null) { 38 | _temp = visiblePercentage > _visibilityPercent; 39 | widget.isVisible(_temp ?? true); 40 | setState(() { 41 | _isVisible = _temp ?? true; 42 | }); 43 | } else { 44 | if (_temp != visiblePercentage > _visibilityPercent) { 45 | _temp = visiblePercentage > _visibilityPercent; 46 | widget.isVisible(_temp ?? true); 47 | setState(() { 48 | _isVisible = _temp ?? true; 49 | }); 50 | } 51 | } 52 | 53 | if (_isVisible && _isFirst) { 54 | _animationController.forward(); 55 | _isFirst = false; 56 | } 57 | // log.d('Widget ${info.key} is $visiblePercentage% visible'); 58 | }, 59 | child: ConstrainedBox( 60 | constraints: BoxConstraints( 61 | minWidth: context.widthInPercent(100), 62 | minHeight: context.heightInPercent(100), 63 | ), 64 | child: Column( 65 | mainAxisAlignment: MainAxisAlignment.center, 66 | crossAxisAlignment: CrossAxisAlignment.start, 67 | mainAxisSize: MainAxisSize.min, 68 | children: [ 69 | Center( 70 | child: 71 | PortfolioTitle(animationController: _animationController), 72 | ), 73 | SpacerV( 74 | value: responsiveSize(context, Dimens.space2, Dimens.space8), 75 | ), 76 | PortfolioDescription( 77 | animationController: _animationController, 78 | ), 79 | SpacerV(value: Dimens.space100), 80 | ], 81 | ), 82 | ), 83 | ), 84 | ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/presentation/widgets/responsive.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../utils/utils.dart'; 4 | 5 | enum DisplayType { 6 | desktop, 7 | tablet, 8 | mobile, 9 | } 10 | 11 | class Responsive extends StatelessWidget { 12 | const Responsive({ 13 | super.key, 14 | required this.builder, 15 | }); 16 | 17 | final Widget Function( 18 | BuildContext context, 19 | BoxConstraints constraints, 20 | ) builder; 21 | 22 | static DisplayType displayTypeOf(BuildContext context) { 23 | final width = MediaQuery.of(context).size.width; 24 | if (width >= const RefinedBreakpoints().desktopNormal) { 25 | return DisplayType.desktop; 26 | } else if (width >= const RefinedBreakpoints().tabletNormal) { 27 | return DisplayType.tablet; 28 | } else { 29 | return DisplayType.mobile; 30 | } 31 | } 32 | 33 | /// Returns a boolean if we are in a display of [DisplayType.desktop]. Used to 34 | /// build adaptive and responsive layouts. 35 | static bool isDesktop(BuildContext context) { 36 | return displayTypeOf(context) == DisplayType.desktop; 37 | } 38 | 39 | /// Returns a boolean if we are in a display of [DisplayType.mobile]. Used to 40 | /// build adaptive and responsive layouts. 41 | static bool isMobile(BuildContext context) { 42 | return displayTypeOf(context) == DisplayType.mobile; 43 | } 44 | 45 | static bool isTablet(BuildContext context) { 46 | return displayTypeOf(context) == DisplayType.tablet; 47 | } 48 | 49 | @override 50 | Widget build(BuildContext context) { 51 | log.d("Display type ${displayTypeOf(context)}"); 52 | return LayoutBuilder( 53 | builder: (context, constraints) { 54 | return builder(context, constraints); 55 | }, 56 | ); 57 | } 58 | } 59 | 60 | class RefinedBreakpoints { 61 | final double mobileSmall; 62 | final double mobileNormal; 63 | final double mobileLarge; 64 | final double mobileExtraLarge; 65 | 66 | final double tabletSmall; 67 | final double tabletNormal; 68 | final double tabletLarge; 69 | final double tabletExtraLarge; 70 | 71 | final double desktopSmall; 72 | final double desktopNormal; 73 | final double desktopLarge; 74 | final double desktopExtraLarge; 75 | 76 | const RefinedBreakpoints({ 77 | this.mobileSmall = 320, 78 | this.mobileNormal = 375, 79 | this.mobileLarge = 414, 80 | this.mobileExtraLarge = 480, 81 | this.tabletSmall = 600, 82 | this.tabletNormal = 768, 83 | this.tabletLarge = 850, 84 | this.tabletExtraLarge = 900, 85 | this.desktopSmall = 950, 86 | this.desktopNormal = 1366, 87 | this.desktopLarge = 3840, 88 | this.desktopExtraLarge = 4096, 89 | }); 90 | 91 | @override 92 | String toString() { 93 | return "Desktop: Small - $desktopSmall Normal - $desktopNormal Large - $desktopLarge ExtraLarge - $desktopExtraLarge\nTablet: Small - $tabletSmall Normal - $tabletNormal Large - $tabletLarge ExtraLarge - $tabletExtraLarge\nMobile: Small - $mobileSmall Normal - $mobileNormal Large - $mobileLarge ExtraLarge - $mobileExtraLarge"; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/gestures.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/services.dart'; 6 | import 'package:flutter_bloc/flutter_bloc.dart'; 7 | import 'package:flutter_localizations/flutter_localizations.dart'; 8 | import 'package:flutter_web_plugins/flutter_web_plugins.dart'; 9 | import 'package:lazycatlabs/core/core.dart'; 10 | import 'package:lazycatlabs/data/data.dart'; 11 | import 'package:lazycatlabs/di/di.dart'; 12 | import 'package:lazycatlabs/presentation/presentation.dart'; 13 | import 'package:lazycatlabs/utils/utils.dart'; 14 | import 'package:shared_preferences/shared_preferences.dart'; 15 | 16 | Future main() async { 17 | /// Register Service locator 18 | 19 | WidgetsFlutterBinding.ensureInitialized(); 20 | await serviceLocator(); 21 | 22 | runZonedGuarded( 23 | /// Lock device orientation to portrait 24 | () => SystemChrome.setPreferredOrientations( 25 | [ 26 | DeviceOrientation.portraitUp, 27 | DeviceOrientation.portraitDown, 28 | ], 29 | ).then((_) async { 30 | /// Load SharedPref before load My App Widget 31 | SharedPreferences.getInstance().then((value) { 32 | initPrefManager(value); 33 | setUrlStrategy(PathUrlStrategy()); 34 | runApp(LzyctApp()); 35 | }); 36 | }), 37 | (error, stackTrace) async {}, 38 | ); 39 | } 40 | 41 | class LzyctApp extends StatelessWidget { 42 | @override 43 | Widget build(BuildContext context) { 44 | return BlocProvider( 45 | create: (_) => sl(), 46 | child: BlocBuilder( 47 | builder: (context, data) { 48 | /// Pass context to appRoute 49 | AppRoute.setStream(context); 50 | 51 | return MaterialApp.router( 52 | routeInformationProvider: AppRoute.router.routeInformationProvider, 53 | routeInformationParser: AppRoute.router.routeInformationParser, 54 | routerDelegate: AppRoute.router.routerDelegate, 55 | scrollBehavior: const MaterialScrollBehavior().copyWith( 56 | dragDevices: { 57 | PointerDeviceKind.mouse, 58 | PointerDeviceKind.touch, 59 | PointerDeviceKind.stylus, 60 | PointerDeviceKind.unknown 61 | }, 62 | ), 63 | localizationsDelegates: const [ 64 | Strings.delegate, 65 | GlobalMaterialLocalizations.delegate, 66 | GlobalWidgetsLocalizations.delegate, 67 | GlobalCupertinoLocalizations.delegate, 68 | ], 69 | debugShowCheckedModeBanner: false, 70 | builder: (BuildContext context, Widget? child) { 71 | final MediaQueryData data = MediaQuery.of(context); 72 | 73 | return MediaQuery( 74 | data: data.copyWith(alwaysUse24HourFormat: true), 75 | child: child!, 76 | ); 77 | }, 78 | title: Constants.get.appName, 79 | theme: themeLight(context), 80 | darkTheme: themeDark(context), 81 | locale: Locale(data.type ?? "en"), 82 | supportedLocales: L10n.all, 83 | useInheritedMediaQuery: true, 84 | themeMode: data.activeTheme.mode, 85 | 86 | /// Check if theme is light or dark first 87 | ); 88 | }, 89 | ), 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/presentation/widgets/animated_widget_shape.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | 4 | class AnimatedWidgetShape extends StatefulWidget { 5 | const AnimatedWidgetShape({ 6 | super.key, 7 | required this.child, 8 | required this.animationController, 9 | required this.width, 10 | required this.height, 11 | this.visibleAnimationCurve = Curves.fastOutSlowIn, 12 | this.invisibleAnimationCurve = Curves.fastOutSlowIn, 13 | this.slideAnimationCurve = Curves.fastOutSlowIn, 14 | this.visibleBoxAnimation, 15 | this.invisibleBoxAnimation, 16 | this.position, 17 | this.boxShape = BoxShape.rectangle, 18 | }); 19 | 20 | final Widget child; 21 | final AnimationController animationController; 22 | final Animation? visibleBoxAnimation; 23 | final Animation? invisibleBoxAnimation; 24 | final Animation? position; 25 | final Curve visibleAnimationCurve; 26 | final Curve invisibleAnimationCurve; 27 | final Curve slideAnimationCurve; 28 | final double width; 29 | final double height; 30 | final BoxShape boxShape; 31 | 32 | @override 33 | State createState() => _AnimatedWidgetShapeState(); 34 | } 35 | 36 | class _AnimatedWidgetShapeState extends State 37 | with SingleTickerProviderStateMixin { 38 | late Animation visibleAnimation = widget.visibleBoxAnimation ?? 39 | Tween(begin: 0, end: widget.width).animate( 40 | CurvedAnimation( 41 | parent: widget.animationController, 42 | curve: Interval( 43 | 0, 44 | 0.35, 45 | curve: widget.visibleAnimationCurve, 46 | ), 47 | ), 48 | ); 49 | 50 | late Animation invisibleAnimation = 51 | invisibleAnimation = widget.invisibleBoxAnimation ?? 52 | Tween(begin: 0, end: widget.width).animate( 53 | CurvedAnimation( 54 | parent: widget.animationController, 55 | curve: Interval( 56 | 0.35, 57 | 0.7, 58 | curve: widget.invisibleAnimationCurve, 59 | ), 60 | ), 61 | ); 62 | 63 | late final Animation _textPositionAnimation = RelativeRectTween( 64 | begin: RelativeRect.fromSize( 65 | Rect.fromLTWH(0, widget.height, widget.width, widget.height), 66 | Size(widget.width, widget.height), 67 | ), 68 | end: RelativeRect.fromSize( 69 | Rect.fromLTWH(0, 0, widget.width, widget.height), 70 | Size(widget.width, widget.height), 71 | ), 72 | ).animate( 73 | CurvedAnimation( 74 | parent: widget.animationController, 75 | curve: Interval(0.6, 1.0, curve: widget.invisibleAnimationCurve), 76 | ), 77 | ); 78 | 79 | @override 80 | Widget build(BuildContext context) { 81 | return SizedBox( 82 | height: widget.height, 83 | child: Stack( 84 | children: [ 85 | AnimatedWidgetSlider( 86 | controller: widget.animationController, 87 | width: widget.width, 88 | height: widget.height, 89 | visibleBoxAnimation: visibleAnimation, 90 | invisibleBoxAnimation: invisibleAnimation, 91 | boxShape: widget.boxShape, 92 | ), 93 | PositionedTransition( 94 | rect: _textPositionAnimation, 95 | child: widget.child, 96 | ), 97 | ], 98 | ), 99 | ); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /assets/images/ic_settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/ic_instagram.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/services/services_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/core/core.dart'; 3 | import 'package:lazycatlabs/data/data.dart'; 4 | import 'package:lazycatlabs/presentation/presentation.dart'; 5 | import 'package:lazycatlabs/utils/utils.dart'; 6 | import 'package:visibility_detector/visibility_detector.dart'; 7 | 8 | class ServicesSection extends StatefulWidget { 9 | const ServicesSection({ 10 | super.key, 11 | required this.isVisible, 12 | }); 13 | 14 | final Function(bool) isVisible; 15 | 16 | @override 17 | State createState() => _ServicesSectionState(); 18 | } 19 | 20 | class _ServicesSectionState extends State 21 | with TickerProviderStateMixin { 22 | bool? _temp; 23 | bool _isVisible = true; 24 | bool _isFirst = true; 25 | final int _visibilityPercent = 50; 26 | 27 | List _listServices = []; 28 | late final AnimationController _animationController = AnimationController( 29 | vsync: this, 30 | duration: durationLong, 31 | ); 32 | 33 | @override 34 | void didChangeDependencies() { 35 | super.didChangeDependencies(); 36 | _listServices = [ 37 | DataHelper( 38 | title: Strings.of(context)!.buildTitle, 39 | desc: Strings.of(context)!.buildDesc, 40 | icon: Icons.build_circle, 41 | ), 42 | DataHelper( 43 | title: Strings.of(context)!.fixTitle, 44 | desc: Strings.of(context)!.fixDesc, 45 | icon: Icons.bug_report_rounded, 46 | ), 47 | DataHelper( 48 | title: Strings.of(context)!.continueTitle, 49 | desc: Strings.of(context)!.continueDesc, 50 | icon: Icons.next_plan, 51 | ), 52 | ]; 53 | } 54 | 55 | @override 56 | Widget build(BuildContext context) { 57 | return SliverToBoxAdapter( 58 | child: VisibilityDetector( 59 | key: const Key("services"), 60 | onVisibilityChanged: (VisibilityInfo info) { 61 | final visiblePercentage = info.visibleFraction * 100; 62 | 63 | if (_temp == null) { 64 | _temp = visiblePercentage > _visibilityPercent; 65 | widget.isVisible(_temp ?? true); 66 | setState(() { 67 | _isVisible = _temp ?? true; 68 | }); 69 | } else { 70 | if (_temp != visiblePercentage > _visibilityPercent) { 71 | _temp = visiblePercentage > _visibilityPercent; 72 | widget.isVisible(_temp ?? true); 73 | setState(() { 74 | _isVisible = _temp ?? true; 75 | }); 76 | } 77 | } 78 | 79 | if (_isVisible && _isFirst) { 80 | _animationController.forward(); 81 | _isFirst = false; 82 | } 83 | // log.d('Widget ${info.key} is $visiblePercentage% visible'); 84 | }, 85 | child: ConstrainedBox( 86 | constraints: BoxConstraints( 87 | minWidth: context.widthInPercent(100), 88 | minHeight: context.heightInPercent(100), 89 | ), 90 | child: Column( 91 | mainAxisAlignment: MainAxisAlignment.center, 92 | crossAxisAlignment: CrossAxisAlignment.start, 93 | mainAxisSize: MainAxisSize.min, 94 | children: [ 95 | Center( 96 | child: ServicesTitle(animationController: _animationController), 97 | ), 98 | SpacerV( 99 | value: responsiveSize(context, Dimens.space8, Dimens.space50), 100 | ), 101 | ServicesDescription( 102 | animationController: _animationController, 103 | listServices: _listServices, 104 | ), 105 | SpacerV(value: Dimens.space100), 106 | ], 107 | ), 108 | ), 109 | ), 110 | ); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /lib/presentation/widgets/animated_text_strikethrough.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/utils/helper/common.dart'; 3 | 4 | class AnimatedTextStrikethrough extends StatefulWidget { 5 | const AnimatedTextStrikethrough({ 6 | super.key, 7 | required this.text, 8 | required this.textStyle, 9 | required this.textStyleHover, 10 | required this.duration, 11 | this.thickness = 2, 12 | required this.onTap, 13 | }); 14 | 15 | final String text; 16 | final TextStyle textStyle; 17 | final TextStyle textStyleHover; 18 | final Duration duration; 19 | final VoidCallback onTap; 20 | final double thickness; 21 | 22 | @override 23 | State createState() => 24 | _AnimatedTextStrikethroughState(); 25 | } 26 | 27 | class _AnimatedTextStrikethroughState extends State 28 | with TickerProviderStateMixin { 29 | late final AnimationController _forwardController = 30 | AnimationController(vsync: this, duration: widget.duration) 31 | ..addListener(() { 32 | setState(() {}); 33 | }); 34 | 35 | late final AnimationController _backwardController = 36 | AnimationController(vsync: this, duration: widget.duration) 37 | ..addListener(() { 38 | setState(() {}); 39 | }) 40 | ..addStatusListener((status) { 41 | if (status == AnimationStatus.completed) { 42 | _backwardController.reset(); 43 | _forwardController.reset(); 44 | } 45 | }); 46 | 47 | late final double _textWidth = 48 | textSize(text: widget.text, style: widget.textStyle).width; 49 | late final double _textHeight = 50 | textSize(text: widget.text, style: widget.textStyle).height; 51 | 52 | late final Animation _forwardAnimation = 53 | Tween(begin: 0, end: _textWidth).animate( 54 | CurvedAnimation(parent: _forwardController, curve: Curves.fastOutSlowIn), 55 | ); 56 | late final Animation _backwardAnimation = 57 | Tween(begin: 0, end: _textWidth).animate( 58 | CurvedAnimation(parent: _backwardController, curve: Curves.fastOutSlowIn), 59 | ); 60 | 61 | bool _isHover = false; 62 | 63 | @override 64 | void dispose() { 65 | _forwardController.dispose(); 66 | _backwardController.dispose(); 67 | super.dispose(); 68 | } 69 | 70 | @override 71 | Widget build(BuildContext context) { 72 | return InkWell( 73 | onTap: widget.onTap.call, 74 | hoverColor: Colors.transparent, 75 | child: MouseRegion( 76 | onEnter: (_) => _onHover(true), 77 | onExit: (_) => _onHover(false), 78 | child: Stack( 79 | children: [ 80 | Positioned( 81 | top: (_textHeight / 2) - widget.thickness, 82 | child: Container( 83 | height: widget.thickness, 84 | color: Theme.of(context).textTheme.bodyText1?.color, 85 | width: _forwardAnimation.value, 86 | ), 87 | ), 88 | Positioned( 89 | top: (_textHeight / 2) - widget.thickness, 90 | child: Container( 91 | height: widget.thickness, 92 | color: Theme.of(context).scaffoldBackgroundColor, 93 | width: _backwardAnimation.value, 94 | ), 95 | ), 96 | Text( 97 | widget.text, 98 | style: _isHover ? widget.textStyleHover : widget.textStyle, 99 | ), 100 | ], 101 | ), 102 | ), 103 | ); 104 | } 105 | 106 | void _onHover(bool hovering) { 107 | if (hovering) { 108 | setState(() { 109 | _forwardController.forward(); 110 | _isHover = hovering; 111 | }); 112 | } else { 113 | setState(() { 114 | _backwardController.forward(); 115 | _isHover = hovering; 116 | }); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: lazycatlabs 2 | description: Lazycat Labs is a place to share about new tech and programming with a lazy way. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.17.1 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | flutter_localizations: 27 | sdk: flutter 28 | flutter_web_plugins: 29 | sdk: flutter 30 | 31 | # Use as default SVG image loader, prefer use SVG as image asset 32 | flutter_svg: ^1.1.6 33 | 34 | # Use as sharedPreferences to save local data 35 | shared_preferences: ^2.0.15 36 | 37 | # Use for Dependencies Injection 38 | get_it: ^7.2.0 39 | 40 | # Use for State Management with BLoC pattern 41 | flutter_bloc: ^8.1.1 42 | equatable: ^2.0.5 43 | 44 | # Use for Time/Date Format 45 | intl: ^0.17.0 46 | 47 | # Use as path reader for Android and iOS 48 | path_provider: ^2.0.11 49 | 50 | # Use for request permission 51 | cached_network_image: ^3.2.2 52 | 53 | # logger 54 | logger: ^1.1.0 55 | 56 | # router 57 | go_router: ^5.1.1 58 | 59 | url_launcher: ^6.1.6 60 | visibility_detector: ^0.3.3 61 | 62 | google_fonts: ^3.0.1 63 | 64 | dev_dependencies: 65 | flutter_test: 66 | sdk: flutter 67 | flutter_launcher_icons: ^0.10.0 68 | lint: ^1.10.0 69 | 70 | 71 | # For information on the generic Dart part of this file, see the 72 | # following page: https://dart.dev/tools/pub/pubspec 73 | 74 | # The following section is specific to Flutter. 75 | flutter: 76 | # The following line ensures that the Material Icons font is 77 | # included with your application, so that you can use the icons in 78 | # the material Icons class. 79 | uses-material-design: true 80 | 81 | # To add assets to your application, add an assets section, like this: 82 | assets: 83 | - assets/images/ 84 | - assets/images/portfolio/oifyoo/ 85 | - assets/images/portfolio/eabsensi/ 86 | - assets/images/portfolio/brupedia/ 87 | - assets/images/portfolio/myananda/ 88 | - assets/images/portfolio/patapaowners/ 89 | - assets/images/portfolio/pataparking/ 90 | - assets/images/portfolio/wautils/ 91 | - assets/static_api/ 92 | 93 | fonts: 94 | - family: VisueltPro 95 | fonts: 96 | - asset: assets/fonts/visuelt/VisueltPro-Thin.ttf 97 | weight: 100 98 | - asset: assets/fonts/visuelt/VisueltPro-ExtraLight.ttf 99 | weight: 200 100 | - asset: assets/fonts/visuelt/VisueltPro-Light.ttf 101 | weight: 300 102 | - asset: assets/fonts/visuelt/VisueltPro-Regular.ttf 103 | weight: 400 104 | - asset: assets/fonts/visuelt/VisueltPro-Medium.ttf 105 | weight: 500 106 | - asset: assets/fonts/visuelt/VisueltPro-Black.ttf 107 | weight: 700 108 | - asset: assets/fonts/visuelt/VisueltPro-Bold.ttf 109 | weight: 800 110 | # 111 | # For details regarding fonts from package dependencies, 112 | # see https://flutter.dev/custom-fonts/#from-packages 113 | -------------------------------------------------------------------------------- /lib/presentation/widgets/animated_text_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | import 'package:lazycatlabs/utils/helper/common.dart'; 4 | 5 | class AnimatedTextBox extends StatefulWidget { 6 | const AnimatedTextBox({ 7 | super.key, 8 | required this.text, 9 | required this.textStyle, 10 | required this.animationController, 11 | this.maxLines = 1, 12 | this.widthFactor = 1, 13 | this.heightFactor = 1, 14 | this.width = double.infinity, 15 | this.visibleAnimationCurve = Curves.fastOutSlowIn, 16 | this.invisibleAnimationCurve = Curves.fastOutSlowIn, 17 | this.slideAnimationCurve = Curves.fastOutSlowIn, 18 | this.visibleBoxAnimation, 19 | this.invisibleBoxAnimation, 20 | this.position, 21 | this.textAlign, 22 | }); 23 | 24 | final String text; 25 | final TextStyle textStyle; 26 | final AnimationController animationController; 27 | final Animation? visibleBoxAnimation; 28 | final Animation? invisibleBoxAnimation; 29 | final Animation? position; 30 | final Curve visibleAnimationCurve; 31 | final Curve invisibleAnimationCurve; 32 | final Curve slideAnimationCurve; 33 | final double width; 34 | final int maxLines; 35 | final double heightFactor; 36 | final double widthFactor; 37 | final TextAlign? textAlign; 38 | 39 | @override 40 | State createState() => _AnimatedTextBoxState(); 41 | } 42 | 43 | class _AnimatedTextBoxState extends State 44 | with SingleTickerProviderStateMixin { 45 | late final Size _size = textSize( 46 | text: widget.text, 47 | style: widget.textStyle, 48 | maxWidth: widget.width, 49 | maxLines: widget.maxLines, 50 | ); 51 | late final double _textWidth = _size.width * widget.widthFactor; 52 | 53 | late final double _textHeight = _size.height * widget.heightFactor; 54 | 55 | late Animation visibleAnimation = widget.visibleBoxAnimation ?? 56 | Tween(begin: 0, end: _textWidth).animate( 57 | CurvedAnimation( 58 | parent: widget.animationController, 59 | curve: Interval( 60 | 0, 61 | 0.35, 62 | curve: widget.visibleAnimationCurve, 63 | ), 64 | ), 65 | ); 66 | 67 | late Animation invisibleAnimation = 68 | invisibleAnimation = widget.invisibleBoxAnimation ?? 69 | Tween(begin: 0, end: _textWidth).animate( 70 | CurvedAnimation( 71 | parent: widget.animationController, 72 | curve: Interval( 73 | 0.35, 74 | 0.7, 75 | curve: widget.invisibleAnimationCurve, 76 | ), 77 | ), 78 | ); 79 | 80 | late final Animation _textPositionAnimation = RelativeRectTween( 81 | begin: RelativeRect.fromSize( 82 | Rect.fromLTWH(0, _textHeight, _textWidth, _textHeight), 83 | Size(_textWidth, _textHeight), 84 | ), 85 | end: RelativeRect.fromSize( 86 | Rect.fromLTWH(0, 0, _textWidth, _textHeight), 87 | Size(_textWidth, _textHeight), 88 | ), 89 | ).animate( 90 | CurvedAnimation( 91 | parent: widget.animationController, 92 | curve: Interval(0.6, 1.0, curve: widget.invisibleAnimationCurve), 93 | ), 94 | ); 95 | 96 | @override 97 | Widget build(BuildContext context) { 98 | return SizedBox( 99 | height: _textHeight, 100 | child: Stack( 101 | children: [ 102 | AnimatedBoxSlider( 103 | controller: widget.animationController, 104 | width: _textWidth, 105 | height: _textHeight, 106 | visibleBoxAnimation: visibleAnimation, 107 | invisibleBoxAnimation: invisibleAnimation, 108 | ), 109 | PositionedTransition( 110 | rect: _textPositionAnimation, 111 | child: Text( 112 | widget.text, 113 | style: widget.textStyle, 114 | textAlign: widget.textAlign, 115 | ), 116 | ), 117 | ], 118 | ), 119 | ); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /lib/presentation/pages/main/profile/profile_description.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/core/core.dart'; 3 | import 'package:lazycatlabs/data/datasources/datasources.dart'; 4 | import 'package:lazycatlabs/di/di.dart'; 5 | import 'package:lazycatlabs/presentation/presentation.dart'; 6 | import 'package:lazycatlabs/utils/utils.dart'; 7 | 8 | class ProfileDescription extends StatelessWidget { 9 | const ProfileDescription({super.key, required this.animationController}); 10 | 11 | final AnimationController animationController; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Padding( 16 | padding: EdgeInsets.symmetric( 17 | horizontal: responsiveSize( 18 | context, 19 | Dimens.space24, 20 | context.widthInPercent(15), 21 | tablet: context.widthInPercent(13), 22 | ), 23 | ), 24 | child: Stack( 25 | children: [ 26 | Positioned( 27 | left: responsiveSize( 28 | context, 29 | Dimens.space50, 30 | Dimens.space120, 31 | tablet: Dimens.space72, 32 | ), 33 | top: responsiveSize(context, -10, -40, tablet: -20), 34 | child: Icon( 35 | Icons.format_quote, 36 | color: Theme.of(context).cardColor, 37 | size: responsiveSize( 38 | context, 39 | Dimens.space50, 40 | Dimens.space150, 41 | tablet: Dimens.space72, 42 | ), 43 | ), 44 | ), 45 | Column( 46 | crossAxisAlignment: CrossAxisAlignment.start, 47 | mainAxisSize: MainAxisSize.min, 48 | children: [ 49 | AnimatedTextBox( 50 | text: Strings.of(context)!.hello, 51 | textStyle: Theme.of(context).textTheme.headline1!.copyWith( 52 | fontSize: responsiveSize( 53 | context, 54 | Dimens.space36, 55 | Dimens.h1, 56 | tablet: Dimens.h3, 57 | ), 58 | ), 59 | animationController: animationController, 60 | ), 61 | AnimatedWidgetShape( 62 | animationController: animationController, 63 | width: context.widthInPercent(100), 64 | height: responsiveSize( 65 | context, 66 | Dimens.space200, 67 | Dimens.space150, 68 | tablet: Dimens.space120, 69 | ), 70 | child: RichText( 71 | text: TextSpan( 72 | text: Strings.of(context)!.profileTitle, 73 | style: Theme.of(context).textTheme.bodyText1!.copyWith( 74 | fontSize: responsiveSize( 75 | context, 76 | Dimens.body1, 77 | Dimens.h6, 78 | ), 79 | fontWeight: FontWeight.w500, 80 | ), 81 | children: [ 82 | TextSpan( 83 | text: Strings.of(context)!.profileDesc, 84 | style: Theme.of(context).textTheme.bodyText1!.copyWith( 85 | fontSize: responsiveSize( 86 | context, 87 | Dimens.body2, 88 | Dimens.space17, 89 | ), 90 | ), 91 | ) 92 | ], 93 | ), 94 | textAlign: TextAlign.justify, 95 | ), 96 | ), 97 | if (sl().locale != "en") 98 | SpacerV(value: Dimens.space16), 99 | AnimatedWidgetShape( 100 | width: Dimens.space250, 101 | height: Dimens.space24, 102 | animationController: animationController, 103 | child: const ProfileButton(), 104 | ), 105 | ], 106 | ), 107 | ], 108 | ), 109 | ); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /lib/presentation/widgets/animated_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:lazycatlabs/presentation/presentation.dart'; 3 | 4 | ///********************************************* 5 | /// Created by ukieTux on 23/04/2020 with ♥ 6 | /// (>’_’)> email : ukie.tux@gmail.com 7 | /// github : https://www.github.com/Lzyct <(’_’<) 8 | ///********************************************* 9 | /// © 2020 | All Right Reserved 10 | class Button extends StatefulWidget { 11 | final String title; 12 | final VoidCallback onPressed; 13 | final double? startWidth; 14 | final double targetWidth; 15 | final double height; 16 | final Color? color; 17 | final Color? titleColor; 18 | final double? fontSize; 19 | final Color? splashColor; 20 | final Offset startOffset; 21 | final Offset targetOffset; 22 | final Widget? child; 23 | final Duration duration; 24 | final BorderRadiusGeometry startBorderRadius; 25 | final BorderRadiusGeometry? endBorderRadius; 26 | 27 | const Button({ 28 | super.key, 29 | required this.title, 30 | required this.onPressed, 31 | this.titleColor, 32 | this.fontSize, 33 | this.splashColor, 34 | this.startOffset = Offset.zero, 35 | this.targetOffset = const Offset(0.1, 0), 36 | this.startWidth = 45, 37 | this.targetWidth = 150, 38 | this.height = 45, 39 | this.child, 40 | this.duration = const Duration( 41 | milliseconds: 300, 42 | ), 43 | this.startBorderRadius = 44 | const BorderRadius.all(Radius.circular(Dimens.cornerButton)), 45 | this.endBorderRadius, 46 | this.color, 47 | }); 48 | 49 | @override 50 | State