From 117b96f75120cada803c85b7c44392021c411c87 Mon Sep 17 00:00:00 2001 From: AlexitoSnow Date: Wed, 7 Feb 2024 03:06:31 -0500 Subject: [PATCH] Portfolio updated --- .github/workflows/launch_web.yaml | 31 ++ .vscode/settings.json | 2 + .../assets/google51501707e62fe96b.html | 1 + snow_portfolio/assets/images/perfil.jpg | Bin 0 -> 57409 bytes snow_portfolio/devtools_options.yaml | 1 + snow_portfolio/i18n/en/extracurricular.json | 20 - snow_portfolio/i18n/en/skills.json | 35 -- snow_portfolio/i18n/en/tabs.json | 6 +- snow_portfolio/i18n/en/technologies.json | 6 + snow_portfolio/i18n/en/volunteering.json | 26 - snow_portfolio/i18n/es/extracurricular.json | 20 - snow_portfolio/i18n/es/skills.json | 35 -- snow_portfolio/i18n/es/tabs.json | 6 +- snow_portfolio/i18n/es/technologies.json | 6 + snow_portfolio/i18n/es/volunteering.json | 26 - snow_portfolio/lib/config/config.dart | 1 - .../lib/config/routes/app_pages.dart | 35 +- .../lib/config/routes/app_routes.dart | 12 +- .../lib/config/utils/bindings_builders.dart | 21 - .../lib/config/utils/extensions.dart | 15 + .../lib/config/widgets/activity_list.dart | 8 +- .../lib/config/widgets/dev_icons_list.dart | 29 +- .../lib/config/widgets/responsive_flex.dart | 4 +- snow_portfolio/lib/domain/models.dart | 3 - .../lib/domain/models/education_model.dart | 11 - .../domain/models/extracurricular_model.dart | 11 - .../lib/domain/models/project_model.dart | 68 +++ .../lib/domain/models/volunteering_model.dart | 10 - .../lib/generated/translations.g.dart | 516 +----------------- snow_portfolio/lib/main.dart | 44 +- .../about_me/about_me_cubit.dart} | 22 +- .../bloc/about_me/about_me_state.dart | 3 + .../lib/presentation/bloc/bloc.dart | 4 + .../presentation/bloc/home/home_cubit.dart | 82 +++ .../presentation/bloc/home/home_state.dart | 12 + .../bloc/projects/projects_cubit.dart | 20 + .../bloc/projects/projects_state.dart | 8 + .../bloc/technologies/technologies_cubit.dart | 40 ++ .../bloc/technologies/technologies_state.dart | 3 + .../presentation/controllers/controllers.dart | 6 - .../extracurricular_controller.dart | 38 -- .../controllers/home/home_controller.dart | 112 ---- .../projects/projects_controller.dart | 67 --- .../controllers/skills/skills_controller.dart | 42 -- .../volunteering/volunteering_controller.dart | 63 --- .../screens/about_me/about_me_view.dart | 71 +-- .../screens/about_me/gretting.dart | 29 + .../extracurricular/extracurricular_view.dart | 29 - .../lib/presentation/screens/home/footer.dart | 60 ++ .../presentation/screens/home/home_view.dart | 154 ++---- .../screens/home/responsive_bar.dart | 86 +-- .../screens/home/social_button.dart | 27 + .../screens/projects/project_card.dart | 88 --- .../screens/projects/project_image_view.dart | 40 -- .../screens/projects/project_page.dart | 76 +++ .../screens/projects/projects_view.dart | 105 +++- .../lib/presentation/screens/screens.dart | 4 +- .../screens/skills/skills_view.dart | 94 ---- .../technologies/technologies_view.dart | 115 ++++ .../volunteering/volunteering_view.dart | 28 - snow_portfolio/pubspec.lock | 56 +- snow_portfolio/pubspec.yaml | 31 +- snow_portfolio/web/index.html | 19 +- 63 files changed, 1014 insertions(+), 1629 deletions(-) create mode 100644 .github/workflows/launch_web.yaml create mode 100644 .vscode/settings.json create mode 100644 snow_portfolio/assets/google51501707e62fe96b.html create mode 100644 snow_portfolio/assets/images/perfil.jpg create mode 100644 snow_portfolio/devtools_options.yaml delete mode 100644 snow_portfolio/i18n/en/extracurricular.json delete mode 100644 snow_portfolio/i18n/en/skills.json create mode 100644 snow_portfolio/i18n/en/technologies.json delete mode 100644 snow_portfolio/i18n/en/volunteering.json delete mode 100644 snow_portfolio/i18n/es/extracurricular.json delete mode 100644 snow_portfolio/i18n/es/skills.json create mode 100644 snow_portfolio/i18n/es/technologies.json delete mode 100644 snow_portfolio/i18n/es/volunteering.json delete mode 100644 snow_portfolio/lib/config/utils/bindings_builders.dart delete mode 100644 snow_portfolio/lib/domain/models/education_model.dart delete mode 100644 snow_portfolio/lib/domain/models/extracurricular_model.dart delete mode 100644 snow_portfolio/lib/domain/models/volunteering_model.dart rename snow_portfolio/lib/presentation/{controllers/about_me/about_me_controller.dart => bloc/about_me/about_me_cubit.dart} (50%) create mode 100644 snow_portfolio/lib/presentation/bloc/about_me/about_me_state.dart create mode 100644 snow_portfolio/lib/presentation/bloc/bloc.dart create mode 100644 snow_portfolio/lib/presentation/bloc/home/home_cubit.dart create mode 100644 snow_portfolio/lib/presentation/bloc/home/home_state.dart create mode 100644 snow_portfolio/lib/presentation/bloc/projects/projects_cubit.dart create mode 100644 snow_portfolio/lib/presentation/bloc/projects/projects_state.dart create mode 100644 snow_portfolio/lib/presentation/bloc/technologies/technologies_cubit.dart create mode 100644 snow_portfolio/lib/presentation/bloc/technologies/technologies_state.dart delete mode 100644 snow_portfolio/lib/presentation/controllers/controllers.dart delete mode 100644 snow_portfolio/lib/presentation/controllers/extracurricular/extracurricular_controller.dart delete mode 100644 snow_portfolio/lib/presentation/controllers/home/home_controller.dart delete mode 100644 snow_portfolio/lib/presentation/controllers/projects/projects_controller.dart delete mode 100644 snow_portfolio/lib/presentation/controllers/skills/skills_controller.dart delete mode 100644 snow_portfolio/lib/presentation/controllers/volunteering/volunteering_controller.dart create mode 100644 snow_portfolio/lib/presentation/screens/about_me/gretting.dart delete mode 100644 snow_portfolio/lib/presentation/screens/extracurricular/extracurricular_view.dart create mode 100644 snow_portfolio/lib/presentation/screens/home/footer.dart create mode 100644 snow_portfolio/lib/presentation/screens/home/social_button.dart delete mode 100644 snow_portfolio/lib/presentation/screens/projects/project_card.dart delete mode 100644 snow_portfolio/lib/presentation/screens/projects/project_image_view.dart create mode 100644 snow_portfolio/lib/presentation/screens/projects/project_page.dart delete mode 100644 snow_portfolio/lib/presentation/screens/skills/skills_view.dart create mode 100644 snow_portfolio/lib/presentation/screens/technologies/technologies_view.dart delete mode 100644 snow_portfolio/lib/presentation/screens/volunteering/volunteering_view.dart diff --git a/.github/workflows/launch_web.yaml b/.github/workflows/launch_web.yaml new file mode 100644 index 0000000..a3989cc --- /dev/null +++ b/.github/workflows/launch_web.yaml @@ -0,0 +1,31 @@ +name: Launch Web + +on: + push: + branches: [ main ] + paths: + - 'snow_portfolio/**' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + flutter-version: "3.16.8" + channel: "stable" + - run: flutter pub get + working-directory: snow_portfolio + - run: flutter build web --web-renderer canvaskit --release + working-directory: snow_portfolio + - run: mkdir docs + - run: cp -r snow_portfolio/build/web/* docs # Comando para copiar el contenido de build/web a docs + - run: cp snow_portfolio/assets/google51501707e62fe96b.html docs/google51501707e62fe96b.html + - run: flutter clean + working-directory: snow_portfolio + - run: git add . + - run: git config user.name AlexitoSnow # Comando para configurar el nombre de usuario de git + - run: git config user.email ganieves@espol.edu.ec # Comando para configurar el email de usuario de git + - run: git commit -m "Deploy web to GitHub Pages" # Comando para hacer un commit con un mensaje + - run: git push origin main \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/snow_portfolio/assets/google51501707e62fe96b.html b/snow_portfolio/assets/google51501707e62fe96b.html new file mode 100644 index 0000000..c907580 --- /dev/null +++ b/snow_portfolio/assets/google51501707e62fe96b.html @@ -0,0 +1 @@ +google-site-verification: google51501707e62fe96b.html \ No newline at end of file diff --git a/snow_portfolio/assets/images/perfil.jpg b/snow_portfolio/assets/images/perfil.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e785b7a8d17b4750b38226c8c9f1fe9d99932cad GIT binary patch literal 57409 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

8d&!*^@R{Lkml z=U$aMiKBv1v$4Bz(y2)%?kfDsS#oioYN0kaa4>6bVhYbtH{Pk{J55$*=C+9LeDUx% zNO=Aa>v8y3QLv8FP1QBH%$G1V%&f6o&E**Z+7y_T2=!8?zJBcGA$$_-}uv=>B4U@B2dQa@#aI#5PxQkfSLSbCC_n=a|^%9V?yj zE{6UvvDZ8?dEv-!?kwl~RN5StPYuIFSC{((e*PB$G3Q$O@r|VI>sUS___N{;RUxxn)b&M3_}|371MxX}v?-{`#-4)H~cT;G(kM?e(46qw{(b5^zt3@<&V6GbnImjd19jo=f!N2fL zi~Iio5^3Hj@!!QALs{1C7Z68fY>gZUf90APgM5Ra&r0CGZEx8Zz<&n(6Q=ls!}=_D z8it{C_LthOtt;G2@;28-Ku*<@YD>;BfsVr(OX0DKTA!R=Jb^AXTMa%aW|<=%Y{-$2 z<=d7R89WU3uFK(kI`4;V=7&UZ7HL*nh+=TkBL4sY&tuOy9qZbD56$64_>rJ$x{iTs ztm)U8f`7N#?nae)RSbPp5%|}xe%+r9d=K!$#U23Ed>5nJ_;S}?g{3j+5D1p&Kk#!mt2 zHu`)T?3VIhMRP00;bbhxz;V!Y{AMs2~4)d!Jn^c*{WbnQ4Bc!WU&LVuN{$2jP5>Bpr{XJhuug}IO9 zi)l#5WKeK;_o!^u#os_OCBnf4xdoIHG?>Qhf(}p6ezkv3v18Da5c~46#xO7d9r&wp z*sZ8Gs668#Ea6ut9kcCSMw_Cm1`*pyEaiBUA1eC{*F36nolvJHW7*jYbV(6NA$CBL z{o;STeg6Q)x4btDvD}rr3nWp$?&HSKe-BFUyf^UDYZh4@ zNKfx)ck`}URYz=TGeg3*;aq;@sKQ3~)gF>yj5v%t5O*>=lOMdGs~3MI?^S-&!bFV+G@!*F~o49${AJ zpUSv9Yk1`m`KRbXuD3_o8lp2{bH}}O#N??RE_ZrNp;$O#r?Fh;KZSUA?H%xD+r`@E zfv-($k?HNILuaouZ^w`ZLt`8h9`)V+$OEl=Hk!ch0e=kjtq&1s3F4m)YT9Ti8)_Dk zTbYO-Ba!kk{{VHcN2V*Xp68WPH%FuRe$^oGUX>}h*TsY|#SvA49aad{e(3UGEWqO( zc^$=d8W)Ks(_~u>E5)|vR3VzieI=r0Qpflifd?Md^55*u@zNg@OR9Ju#8#H@c&k8w zz4g`lmfx|2QJ5x8vZEY=Fiz2&3i^ja)*9j)eLnA7JDG`&*IEm85hUkgT_)Z5$zPa* z#~_;ZBWoTkv}bz_#=9DVWz+5u{LICgG6!CmJlEux{1iLjzNO%AjvB_kZK03Dz9@{| ztUH0(Hqay~=uCl|Z=(wRP15btNAqoN^w})@$r@N?vwxL99Oaj5ZTwH;UL*T&dE zfcP7C1%{%xm--~%+E(I7hnPZxzAS;BgQ@3=!lXHth0>j*en0#X@nw&Ke1D|f>ggo9 zI$RiaI8*OEjHuCF1s&hYc`!Y3Uu@i3zr)WQY0fn@y1B5DI}K6>elFT5m1CKIye_Q_ zXLmx%M^TFW{{WXW>Vjbc+MVS>uOJb@Irbd>HTMs~--g~N_|@8 z4i3@)uhOsC*6YK*B=E+UZ34WLTH4%4VwZ#GxYDFQy|b8~ylv*pTTk6okEnX`UmkwU zI)8_JLRDtFu<-ZV8f`nodR#y0IvXBDcM3jdfVTmMDbRepR(Omwr7mcZ3eoC$Z^IuC z{5SafV~Z~hriJ4aRhoGGCw^g^|(eBn2X~*>*?Qwe-9z>exVab;*S>}FXjHu z*OkmC-z+kIxvmAjW?$^RO50G^^u0B82*NM?BpMC6&1rZ~8}2P|JhpBd&4j7kPfTR} zC*U1FQPO-l4VI%U)3hh|UVXv10Xt#XZX?-=Bh=Sb3T_KimaB`{=p>x9W1p`Wtoa}2 zt8+h4!l+62tFat}Q#MChhMwHhGm7bp6^{=6v^;sI=)VZ%)30?KmbuoZTU#ZwLW


eHS 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 N9t$@tF9QFY{(r4L$u9r^ literal 0 HcmV?d00001 diff --git a/snow_portfolio/devtools_options.yaml b/snow_portfolio/devtools_options.yaml new file mode 100644 index 0000000..7e7e7f6 --- /dev/null +++ b/snow_portfolio/devtools_options.yaml @@ -0,0 +1 @@ +extensions: diff --git a/snow_portfolio/i18n/en/extracurricular.json b/snow_portfolio/i18n/en/extracurricular.json deleted file mode 100644 index b9a704e..0000000 --- a/snow_portfolio/i18n/en/extracurricular.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "act1": { - "name": " Vol. I", - "institution": "Guayaquil Tech", - "date": "{{startDate}} to {{endDate}}", - "description": "Participation in the programming competition in a challenge proposed by the company Publifyer, contributing to the development of our project's API, which consumed services from OpenAI." - }, - "act2": { - "name": "NASA Space Apps Challenge Guayaquil 2023", - "institution": "CORPCITI", - "date": "{{startDate}} to {{endDate}}", - "description": "Leader and participant in the local programming competition Space Apps in the challenge 'Planetary Tourism Office', designing the frontend interface." - }, - "act3": { - "name": "IOT&AI Latin America Competition 2023", - "institution": "IEEE TEMS", - "date": "{{startDate}} to {{endDate}}", - "description": "Design of the frontend interface for the project 'CrimeBuster', which consists of a real-time crime detection system using artificial intelligence and machine learning." - } -} \ No newline at end of file diff --git a/snow_portfolio/i18n/en/skills.json b/snow_portfolio/i18n/en/skills.json deleted file mode 100644 index 8e33ada..0000000 --- a/snow_portfolio/i18n/en/skills.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "headers": { - "education": "Education", - "softskills": "Soft Skills", - "languages": "Languages" - }, - "education": { - "university": { - "name": "Computer Science Engineering", - "institution": "ESPOL", - "date": "{{startDate}} to Present", - "description": "4th semester" - }, - "course": { - "name": "Data Engineering", - "institution": "SEE", - "date": "{{startDate}} to {{endDate}}", - "description": "Data Architecture\nData Modeling and Design\nAnalytical Processing\nData Quality\nBig Data Processing with Apache Spark\nData Pipelines with Apache Airflow" - } - }, - "softskills": [ - "Teamwork", - "Leadership", - "Adaptability", - "Problem Solving", - "Critical Thinking", - "Empathy", - "Project Management", - "Results Oriented" - ], - "languages": [ - "Spanish", - "English" - ] -} \ No newline at end of file diff --git a/snow_portfolio/i18n/en/tabs.json b/snow_portfolio/i18n/en/tabs.json index 3059007..2f14577 100644 --- a/snow_portfolio/i18n/en/tabs.json +++ b/snow_portfolio/i18n/en/tabs.json @@ -1,7 +1,5 @@ { "about": "About", - "skills": "Skills", - "projects": "Projects", - "extracurricular": "Extracurricular", - "volunteering": "Volunteering" + "technologies": "Technologies", + "projects": "Projects" } \ No newline at end of file diff --git a/snow_portfolio/i18n/en/technologies.json b/snow_portfolio/i18n/en/technologies.json new file mode 100644 index 0000000..58dfb71 --- /dev/null +++ b/snow_portfolio/i18n/en/technologies.json @@ -0,0 +1,6 @@ +{ + "languages": "Languages", + "frameworks": "Frameworks", + "databases": "Data Bases", + "tools": "Tools" +} \ No newline at end of file diff --git a/snow_portfolio/i18n/en/volunteering.json b/snow_portfolio/i18n/en/volunteering.json deleted file mode 100644 index a0333b2..0000000 --- a/snow_portfolio/i18n/en/volunteering.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "vol1": { - "name": "Vice President", - "institution": "IEEE ESPOL Computer Society", - "date": "{{startDate}} to {{endDate}}", - "description": "Project management, communication with students." - }, - "vol2": { - "name": "Contributor in the 12th edition of PyWeekend 2023", - "institution": "ESPOL", - "date": "{{startDate}} to {{endDate}}", - "description": "Contributed to the development of the semifinal challenge of the Python programming competition. Also, helped guide participants on the day of the competition." - }, - "vol3": { - "name": "Guide at Django Girls", - "institution": "Open Lab", - "date": "{{startDate}} to {{endDate}}", - "description": "Contributed to ensure that participants successfully complete the introductory Django tutorial." - }, - "vol4": { - "name": "Contributor in the 2nd edition of PyTime IoT", - "institution": "Niot ESPOL", - "date": "{{startDate}} to {{endDate}}", - "description": "Provided support to students in topics related to the Python programming language and resolved their inquiries during their learning process." - } -} diff --git a/snow_portfolio/i18n/es/extracurricular.json b/snow_portfolio/i18n/es/extracurricular.json deleted file mode 100644 index c6fd85d..0000000 --- a/snow_portfolio/i18n/es/extracurricular.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "act1": { - "name": " Vol. I", - "institution": "Guayaquil Tech", - "date": "{{startDate}} a {{endDate}}", - "description": "Participación en la competencia de programación en un desafío propuesto por la empresa Publifyer, contribuyendo al desarrollo de la API de nuestro proyecto, misma que consumía los servicios de OpenAI." - }, - "act2": { - "name": "NASA Space Apps Challenge Guayaquil 2023", - "institution": "CORPCITI", - "date": "{{startDate}} a {{endDate}}", - "description": "Líder y participante en la competencia de programación local Space Apps en el desafío “Planetary Tourism Office”, diseñando la interfaz frontend." - }, - "act3": { - "name": "Concurso IOT&AI Latinoamérica 2023", - "institution": "IEEE TEMS", - "date": "{{startDate}} a {{endDate}}", - "description": "Diseño de la interfaz frontend para el proyecto “CrimeBuster”, el cual consiste en un sistema de detección de crímenes en tiempo real, utilizando inteligencia artificial y aprendizaje automático." - } -} \ No newline at end of file diff --git a/snow_portfolio/i18n/es/skills.json b/snow_portfolio/i18n/es/skills.json deleted file mode 100644 index cd8453a..0000000 --- a/snow_portfolio/i18n/es/skills.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "headers": { - "education": "Educación", - "softskills": "Habilidades Blandas", - "languages": "Idiomas" - }, - "education": { - "university": { - "name": "Ingeniería en Ciencias de la Computación", - "institution": "ESPOL", - "date": "{{startDate}} hasta la actualidad", - "description": "4to semestre" - }, - "course": { - "name": "Ingeniería de Datos", - "institution": "SEE", - "date": "{{startDate}} hasta {{endDate}}", - "description": "Arquitectura de Datos\nModelado y Diseño de Datos\nProcesamiento Analítico\nCalidad de Datos\nProcesamiento de Big Data con Apache Spark\nTuberías de Datos con Apache Airflow" - } - }, - "softskills": [ - "Trabajo en Equipo", - "Liderazgo", - "Adaptabilidad", - "Resolución de Problemas", - "Pensamiento Crítico", - "Empatía", - "Gestión de Proyectos", - "Orientado a Resultados" - ], - "languages": [ - "Español", - "Inglés" - ] -} \ No newline at end of file diff --git a/snow_portfolio/i18n/es/tabs.json b/snow_portfolio/i18n/es/tabs.json index 1542e5c..b0d4bb6 100644 --- a/snow_portfolio/i18n/es/tabs.json +++ b/snow_portfolio/i18n/es/tabs.json @@ -1,7 +1,5 @@ { "about": "Sobre mí", - "skills": "Habilidades", - "projects": "Proyectos", - "extracurricular": "Extracurriculares", - "volunteering": "Voluntariado" + "technologies": "Tecnologías", + "projects": "Proyectos" } \ No newline at end of file diff --git a/snow_portfolio/i18n/es/technologies.json b/snow_portfolio/i18n/es/technologies.json new file mode 100644 index 0000000..c2d4a98 --- /dev/null +++ b/snow_portfolio/i18n/es/technologies.json @@ -0,0 +1,6 @@ +{ + "languages": "Lenguajes", + "frameworks": "Marcos de Trabajo", + "databases": "Bases de Datos", + "tools": "Herramientas" +} \ No newline at end of file diff --git a/snow_portfolio/i18n/es/volunteering.json b/snow_portfolio/i18n/es/volunteering.json deleted file mode 100644 index 1d9e2b0..0000000 --- a/snow_portfolio/i18n/es/volunteering.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "vol1": { - "name": "Vicepresidente", - "institution": "IEEE ESPOL Computer Society", - "date": "{{startDate}} a {{endDate}}", - "description": "Dirección de proyectos, comunicación con estudiantes." - }, - "vol2": { - "name": "Colaborador en la 12va edición de PyWeekend 2023", - "institution": "ESPOL", - "date": "{{startDate}} a {{endDate}}", - "description": "Contribuí en la elaboración del desafío de la semifinal de la competencia de programación en Python. Además, ayudé a orientar a los participantes el día de la competencia." - }, - "vol3": { - "name": "Guía en Django Girls", - "institution": "Open Lab", - "date": "{{startDate}} a {{endDate}}", - "description": "Contribuí a que las participantes puedan desarrollar, satisfactoriamente, el tutorial introductorio a Django." - }, - "vol4": { - "name": "Colaborador en la 2da edición de PyTime IoT", - "institution": "Niot ESPOL", - "date": "{{startDate}} a {{endDate}}", - "description": "Dar soporte a los estudiantes en temas relacionados al lenguaje de programación Python y resolver sus inquietudes durante su proceso de aprendizaje." - } -} diff --git a/snow_portfolio/lib/config/config.dart b/snow_portfolio/lib/config/config.dart index f5fe7aa..e05ad20 100644 --- a/snow_portfolio/lib/config/config.dart +++ b/snow_portfolio/lib/config/config.dart @@ -1,6 +1,5 @@ export 'routes/app_pages.dart'; -export 'utils/bindings_builders.dart'; export 'utils/constants.dart'; export 'utils/extensions.dart'; diff --git a/snow_portfolio/lib/config/routes/app_pages.dart b/snow_portfolio/lib/config/routes/app_pages.dart index 531509a..4bb50be 100644 --- a/snow_portfolio/lib/config/routes/app_pages.dart +++ b/snow_portfolio/lib/config/routes/app_pages.dart @@ -1,4 +1,4 @@ -import 'package:get/get.dart'; +import 'package:go_router/go_router.dart'; import 'package:snow_portfolio/presentation/screens/screens.dart'; // ignore_for_file: constant_identifier_names @@ -7,12 +7,31 @@ part 'app_routes.dart'; class AppPages { AppPages._(); - static const INITIAL = Routes.HOME; + static const INITIAL = Routes.ABOUT; - static final routes = [ - GetPage( - name: _Paths.HOME, - page: () => const HomeView(), - ), - ]; + static final router = GoRouter( + initialLocation: INITIAL, + routes: [ + ShellRoute( + routes: [ + GoRoute( + path: Routes.ABOUT, + name: Routes.ABOUT, + builder: (_, __) => const AboutMeView(), + ), + GoRoute( + path: Routes.TECHNOLOGIES, + name: Routes.TECHNOLOGIES, + builder: (_, __) => TechnologiesView(), + ), + GoRoute( + path: Routes.PROJECTS, + name: Routes.PROJECTS, + builder: (_, __) => const ProjectsView(), + ), + ], + builder: (_, __, child) => HomeView(page: child), + ), + ], + ); } diff --git a/snow_portfolio/lib/config/routes/app_routes.dart b/snow_portfolio/lib/config/routes/app_routes.dart index 3e2ddd3..d711595 100644 --- a/snow_portfolio/lib/config/routes/app_routes.dart +++ b/snow_portfolio/lib/config/routes/app_routes.dart @@ -1,14 +1,10 @@ // ignore_for_file: constant_identifier_names part of 'app_pages.dart'; -// DO NOT EDIT. This is code generated via package:get_cli/get_cli.dart abstract class Routes { - Routes._(); - static const HOME = _Paths.HOME; -} - -abstract class _Paths { - _Paths._(); - static const HOME = '/'; + static const HOME = '/alexander-nieves/'; + static const ABOUT = '${HOME}about'; + static const TECHNOLOGIES = '${HOME}technologies'; + static const PROJECTS = '${HOME}projects'; } diff --git a/snow_portfolio/lib/config/utils/bindings_builders.dart b/snow_portfolio/lib/config/utils/bindings_builders.dart deleted file mode 100644 index 81b0f37..0000000 --- a/snow_portfolio/lib/config/utils/bindings_builders.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:get/get.dart'; - -import '../../presentation/controllers/about_me/about_me_controller.dart'; -import '../../presentation/controllers/extracurricular/extracurricular_controller.dart'; -import '../../presentation/controllers/home/home_controller.dart'; -import '../../presentation/controllers/projects/projects_controller.dart'; -import '../../presentation/controllers/skills/skills_controller.dart'; -import '../../presentation/controllers/volunteering/volunteering_controller.dart'; - -abstract class BindingsBuilders { - static BindingsBuilder get bindings { - return BindingsBuilder(() { - Get.put(HomeController()); - Get.put(AboutMeController()); - Get.lazyPut(() => ProjectsController()); - Get.lazyPut(() => VolunteeringController()); - Get.lazyPut(() => ExtracurricularController()); - Get.lazyPut(() => SkillsController()); - }); - } -} diff --git a/snow_portfolio/lib/config/utils/extensions.dart b/snow_portfolio/lib/config/utils/extensions.dart index 8e74fc1..84075f3 100644 --- a/snow_portfolio/lib/config/utils/extensions.dart +++ b/snow_portfolio/lib/config/utils/extensions.dart @@ -1,6 +1,14 @@ +import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; extension WidgetExtensions on Widget { + + Widget center() { + return Center( + child: this, + ); + } + Widget paddingAll(double padding) { return Padding( padding: EdgeInsets.all(padding), @@ -68,4 +76,11 @@ extension WidgetExtensions on Widget { child: this, ); } +} + +extension EasyContext on BuildContext { + Size get mediaQuerySize => MediaQuery.of(this).size; + double get height => mediaQuerySize.height; + double get width => mediaQuerySize.width; + ThemeData get theme => Theme.of(this); } \ No newline at end of file diff --git a/snow_portfolio/lib/config/widgets/activity_list.dart b/snow_portfolio/lib/config/widgets/activity_list.dart index aa99b64..cfcfa85 100644 --- a/snow_portfolio/lib/config/widgets/activity_list.dart +++ b/snow_portfolio/lib/config/widgets/activity_list.dart @@ -1,9 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:get/get.dart'; +import 'package:snow_portfolio/config/config.dart'; import 'package:snow_portfolio/domain/models/activity_model.dart'; -import 'package:snow_portfolio/config/utils/constants.dart'; -class ActivityList extends GetView { +class ActivityList extends StatelessWidget { final List activities; const ActivityList( this.activities, { @@ -13,9 +12,8 @@ class ActivityList extends GetView { @override Widget build(BuildContext context) { isPhone = context.width <= 800; - textScaleFactor = context.textScaleFactor; return SizedBox( - height: Get.height, + height: context.height, child: ListView( children: List.generate( activities.length, diff --git a/snow_portfolio/lib/config/widgets/dev_icons_list.dart b/snow_portfolio/lib/config/widgets/dev_icons_list.dart index ca3b4ae..271060e 100644 --- a/snow_portfolio/lib/config/widgets/dev_icons_list.dart +++ b/snow_portfolio/lib/config/widgets/dev_icons_list.dart @@ -1,14 +1,15 @@ import 'package:dev_icons/dev_icons.dart'; import 'package:flutter/material.dart'; -import 'package:get/get.dart'; +import 'package:snow_portfolio/config/config.dart'; class DevIconsList extends StatelessWidget { const DevIconsList({ super.key, - required this.iconList, + required this.iconList, this.radius, }); final List iconList; + final double? radius; @override Widget build(BuildContext context) { @@ -18,23 +19,24 @@ class DevIconsList extends StatelessWidget { iconList.length, (index) => Tooltip( message: iconList[index], - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), - child: CircleAvatar( - maxRadius: isPhone ? 15 : 25, - child: Icon( - tecnologiesMap[iconList[index]], - size: isPhone ? 15 : 35, - ), - ), + decoration: BoxDecoration( + color: mainColor.withOpacity(0.8), + borderRadius: BorderRadius.circular(8.0), ), + child: CircleAvatar( + maxRadius: radius ?? (isPhone ? 18 : 25), + child: Icon( + technologiesMap[iconList[index]], + size: radius ?? (isPhone ? 18 : 35), + ), + ).paddingSymmetric(horizontal: 8.0, vertical: 4.0), ), ), ); } } -const Map tecnologiesMap = { +const Map technologiesMap = { 'java': DevIcons.javaPlain, 'flutter': DevIcons.flutterPlain, 'springboot': DevIcons.springPlain, @@ -44,4 +46,7 @@ const Map tecnologiesMap = { 'postgresql': DevIcons.postgresqlPlain, 'git': DevIcons.gitPlain, 'sql server': DevIcons.microsoftsqlserverPlain, + 'github': DevIcons.githubOriginal, + 'firebase': DevIcons.firebasePlain, + 'visual studio code': DevIcons.visualstudioPlain, }; diff --git a/snow_portfolio/lib/config/widgets/responsive_flex.dart b/snow_portfolio/lib/config/widgets/responsive_flex.dart index 9100302..717bbef 100644 --- a/snow_portfolio/lib/config/widgets/responsive_flex.dart +++ b/snow_portfolio/lib/config/widgets/responsive_flex.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:get/get.dart'; +import 'package:snow_portfolio/config/config.dart'; class ResponsiveFlex extends StatelessWidget { const ResponsiveFlex( @@ -13,7 +13,7 @@ class ResponsiveFlex extends StatelessWidget { Widget build(BuildContext context) { final isPhone = context.width <= 800; return SizedBox( - height: Get.height, + height: context.height, child: Flex( mainAxisSize: MainAxisSize.max, mainAxisAlignment: mainAxisAlignment, diff --git a/snow_portfolio/lib/domain/models.dart b/snow_portfolio/lib/domain/models.dart index 219681c..6b85447 100644 --- a/snow_portfolio/lib/domain/models.dart +++ b/snow_portfolio/lib/domain/models.dart @@ -1,5 +1,2 @@ export 'models/activity_model.dart'; -export 'models/education_model.dart'; -export 'models/extracurricular_model.dart'; export 'models/project_model.dart'; -export 'models/volunteering_model.dart'; diff --git a/snow_portfolio/lib/domain/models/education_model.dart b/snow_portfolio/lib/domain/models/education_model.dart deleted file mode 100644 index 2481632..0000000 --- a/snow_portfolio/lib/domain/models/education_model.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'activity_model.dart'; - -class Education extends Activity { - Education({ - super.name, - super.institution, - super.date, - super.endDate, - super.description, - }); -} diff --git a/snow_portfolio/lib/domain/models/extracurricular_model.dart b/snow_portfolio/lib/domain/models/extracurricular_model.dart deleted file mode 100644 index d07e4d8..0000000 --- a/snow_portfolio/lib/domain/models/extracurricular_model.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'activity_model.dart'; - -class Extracurricular extends Activity { - Extracurricular({ - super.name, - super.institution, - super.date, - super.endDate, - super.description, - }); -} diff --git a/snow_portfolio/lib/domain/models/project_model.dart b/snow_portfolio/lib/domain/models/project_model.dart index 8132c7c..d543d66 100644 --- a/snow_portfolio/lib/domain/models/project_model.dart +++ b/snow_portfolio/lib/domain/models/project_model.dart @@ -1,3 +1,5 @@ +import '../../generated/translations.g.dart'; + class Project { String? title; String? description; @@ -29,6 +31,72 @@ class Project { data['technologies'] = technologies; return data; } + + static List get projectItems => [ + Project( + title: texts.project.snowNotepad.title, + description: texts.project.snowNotepad.description, + image: texts.project.snowNotepad + .image(imagePath: '$imagePath/snownotepad_project.jpg'), + repository: texts.project.snowNotepad + .repository(repository: '$github/SnowNotepad'), + technologies: texts.project.snowNotepad.technologies, + ), + Project( + title: texts.project.crimeBuster.title, + description: texts.project.crimeBuster.description, + image: texts.project.crimeBuster + .image(imagePath: '$imagePath/crimebuster_project.jpg'), + repository: texts.project.crimeBuster + .repository(repository: '$github/CrimeBuster-IoTEngine'), + technologies: texts.project.crimeBuster.technologies, + ), + Project( + title: texts.project.polaris.title, + description: texts.project.polaris.description, + image: texts.project.polaris + .image(imagePath: '$imagePath/polaris_project.png'), + repository: texts.project.polaris + .repository(repository: '$github/proyect_polaris'), + technologies: texts.project.polaris.technologies, + ), + Project( + title: texts.project.notepadWeb.title, + description: texts.project.notepadWeb.description, + image: texts.project.notepadWeb + .image(imagePath: '$imagePath/notepad_web_project.jpg'), + repository: texts.project.notepadWeb + .repository(repository: '$github/notepad_web_app'), + technologies: texts.project.notepadWeb.technologies, + ), + Project( + title: texts.project.notepadAPI.title, + description: texts.project.notepadAPI.description, + image: texts.project.notepadAPI + .image(imagePath: '$imagePath/notepad_api_project.png'), + repository: texts.project.notepadAPI + .repository(repository: '$github/notepad_api'), + technologies: texts.project.notepadAPI.technologies, + ), + Project( + title: texts.project.chasing30.title, + description: texts.project.chasing30.description, + image: texts.project.chasing30 + .image(imagePath: '$imagePath/chasing30_project.png'), + repository: texts.project.chasing30 + .repository(repository: '$github/PyWeekend-ESPOL'), + technologies: texts.project.chasing30.technologies, + ), + Project( + title: texts.project.snakeGame.title, + description: texts.project.snakeGame.description, + image: texts.project.snakeGame + .image(imagePath: '$imagePath/snake_project.jpeg'), + repository: texts.project.snakeGame + .repository(repository: '$github/proyecto-aniversarioIEEE-Snake'), + technologies: texts.project.snakeGame.technologies, + ), + ]; } const String github = 'https://www.github.com/AlexitoSnow'; diff --git a/snow_portfolio/lib/domain/models/volunteering_model.dart b/snow_portfolio/lib/domain/models/volunteering_model.dart deleted file mode 100644 index 42716b1..0000000 --- a/snow_portfolio/lib/domain/models/volunteering_model.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'activity_model.dart'; - -class Volunteering extends Activity { - Volunteering({ - super.name, - super.institution, - super.date, - super.description, - }); -} diff --git a/snow_portfolio/lib/generated/translations.g.dart b/snow_portfolio/lib/generated/translations.g.dart index 96cdfe5..3fad464 100644 --- a/snow_portfolio/lib/generated/translations.g.dart +++ b/snow_portfolio/lib/generated/translations.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 2 -/// Strings: 196 (98 per locale) +/// Strings: 102 (51 per locale) /// -/// Built on 2024-01-10 at 00:17 UTC +/// Built on 2024-02-07 at 03:19 UTC // coverage:ignore-file // ignore_for_file: type=lint @@ -149,11 +149,9 @@ class Translations implements BaseTranslations { // Translations late final _TranslationsAboutEs about = _TranslationsAboutEs._(_root); - late final _TranslationsExtracurricularEs extracurricular = _TranslationsExtracurricularEs._(_root); late final _TranslationsProjectEs project = _TranslationsProjectEs._(_root); - late final _TranslationsSkillsEs skills = _TranslationsSkillsEs._(_root); late final _TranslationsTabsEs tabs = _TranslationsTabsEs._(_root); - late final _TranslationsVolunteeringEs volunteering = _TranslationsVolunteeringEs._(_root); + late final _TranslationsTechnologiesEs technologies = _TranslationsTechnologiesEs._(_root); } // Path: about @@ -168,18 +166,6 @@ class _TranslationsAboutEs { String get presentation => 'Aspiro a ser una persona capaz de motivar, liderar y enseñar a los demás. Estoy interesado en el desarrollo backend y abierto a aprender de las distintas áreas en las que pueda especializarme. Me gusta involucrarme en actividades comunitarias y de aprendizaje diversificado. Además, en mis tiempos libres me dedico a desarrollar proyectos personales.'; } -// Path: extracurricular -class _TranslationsExtracurricularEs { - _TranslationsExtracurricularEs._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - late final _TranslationsExtracurricularAct1Es act1 = _TranslationsExtracurricularAct1Es._(_root); - late final _TranslationsExtracurricularAct2Es act2 = _TranslationsExtracurricularAct2Es._(_root); - late final _TranslationsExtracurricularAct3Es act3 = _TranslationsExtracurricularAct3Es._(_root); -} - // Path: project class _TranslationsProjectEs { _TranslationsProjectEs._(this._root); @@ -196,31 +182,6 @@ class _TranslationsProjectEs { late final _TranslationsProjectSnakeGameEs snakeGame = _TranslationsProjectSnakeGameEs._(_root); } -// Path: skills -class _TranslationsSkillsEs { - _TranslationsSkillsEs._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - late final _TranslationsSkillsHeadersEs headers = _TranslationsSkillsHeadersEs._(_root); - late final _TranslationsSkillsEducationEs education = _TranslationsSkillsEducationEs._(_root); - List get softskills => [ - 'Trabajo en Equipo', - 'Liderazgo', - 'Adaptabilidad', - 'Resolución de Problemas', - 'Pensamiento Crítico', - 'Empatía', - 'Gestión de Proyectos', - 'Orientado a Resultados', - ]; - List get languages => [ - 'Español', - 'Inglés', - ]; -} - // Path: tabs class _TranslationsTabsEs { _TranslationsTabsEs._(this._root); @@ -229,62 +190,21 @@ class _TranslationsTabsEs { // Translations String get about => 'Sobre mí'; - String get skills => 'Habilidades'; + String get technologies => 'Tecnologías'; String get projects => 'Proyectos'; - String get extracurricular => 'Extracurriculares'; - String get volunteering => 'Voluntariado'; -} - -// Path: volunteering -class _TranslationsVolunteeringEs { - _TranslationsVolunteeringEs._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - late final _TranslationsVolunteeringVol1Es vol1 = _TranslationsVolunteeringVol1Es._(_root); - late final _TranslationsVolunteeringVol2Es vol2 = _TranslationsVolunteeringVol2Es._(_root); - late final _TranslationsVolunteeringVol3Es vol3 = _TranslationsVolunteeringVol3Es._(_root); - late final _TranslationsVolunteeringVol4Es vol4 = _TranslationsVolunteeringVol4Es._(_root); } -// Path: extracurricular.act1 -class _TranslationsExtracurricularAct1Es { - _TranslationsExtracurricularAct1Es._(this._root); +// Path: technologies +class _TranslationsTechnologiesEs { + _TranslationsTechnologiesEs._(this._root); final Translations _root; // ignore: unused_field // Translations - String get name => ' Vol. I'; - String get institution => 'Guayaquil Tech'; - String date({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - String get description => 'Participación en la competencia de programación en un desafío propuesto por la empresa Publifyer, contribuyendo al desarrollo de la API de nuestro proyecto, misma que consumía los servicios de OpenAI.'; -} - -// Path: extracurricular.act2 -class _TranslationsExtracurricularAct2Es { - _TranslationsExtracurricularAct2Es._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - String get name => 'NASA Space Apps Challenge Guayaquil 2023'; - String get institution => 'CORPCITI'; - String date({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - String get description => 'Líder y participante en la competencia de programación local Space Apps en el desafío “Planetary Tourism Office”, diseñando la interfaz frontend.'; -} - -// Path: extracurricular.act3 -class _TranslationsExtracurricularAct3Es { - _TranslationsExtracurricularAct3Es._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - String get name => 'Concurso IOT&AI Latinoamérica 2023'; - String get institution => 'IEEE TEMS'; - String date({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - String get description => 'Diseño de la interfaz frontend para el proyecto “CrimeBuster”, el cual consiste en un sistema de detección de crímenes en tiempo real, utilizando inteligencia artificial y aprendizaje automático.'; + String get languages => 'Lenguajes'; + String get frameworks => 'Marcos de Trabajo'; + String get databases => 'Bases de Datos'; + String get tools => 'Herramientas'; } // Path: project.snowNotepad @@ -405,107 +325,6 @@ class _TranslationsProjectSnakeGameEs { ]; } -// Path: skills.headers -class _TranslationsSkillsHeadersEs { - _TranslationsSkillsHeadersEs._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - String get education => 'Educación'; - String get softskills => 'Habilidades Blandas'; - String get languages => 'Idiomas'; -} - -// Path: skills.education -class _TranslationsSkillsEducationEs { - _TranslationsSkillsEducationEs._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - late final _TranslationsSkillsEducationUniversityEs university = _TranslationsSkillsEducationUniversityEs._(_root); - late final _TranslationsSkillsEducationCourseEs course = _TranslationsSkillsEducationCourseEs._(_root); -} - -// Path: volunteering.vol1 -class _TranslationsVolunteeringVol1Es { - _TranslationsVolunteeringVol1Es._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - String get name => 'Vicepresidente'; - String get institution => 'IEEE ESPOL Computer Society'; - String date({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - String get description => 'Dirección de proyectos, comunicación con estudiantes.'; -} - -// Path: volunteering.vol2 -class _TranslationsVolunteeringVol2Es { - _TranslationsVolunteeringVol2Es._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - String get name => 'Colaborador en la 12va edición de PyWeekend 2023'; - String get institution => 'ESPOL'; - String date({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - String get description => 'Contribuí en la elaboración del desafío de la semifinal de la competencia de programación en Python. Además, ayudé a orientar a los participantes el día de la competencia.'; -} - -// Path: volunteering.vol3 -class _TranslationsVolunteeringVol3Es { - _TranslationsVolunteeringVol3Es._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - String get name => 'Guía en Django Girls'; - String get institution => 'Open Lab'; - String date({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - String get description => 'Contribuí a que las participantes puedan desarrollar, satisfactoriamente, el tutorial introductorio a Django.'; -} - -// Path: volunteering.vol4 -class _TranslationsVolunteeringVol4Es { - _TranslationsVolunteeringVol4Es._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - String get name => 'Colaborador en la 2da edición de PyTime IoT'; - String get institution => 'Niot ESPOL'; - String date({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - String get description => 'Dar soporte a los estudiantes en temas relacionados al lenguaje de programación Python y resolver sus inquietudes durante su proceso de aprendizaje.'; -} - -// Path: skills.education.university -class _TranslationsSkillsEducationUniversityEs { - _TranslationsSkillsEducationUniversityEs._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - String get name => 'Ingeniería en Ciencias de la Computación'; - String get institution => 'ESPOL'; - String date({required Object startDate}) => '${startDate} hasta la actualidad'; - String get description => '4to semestre'; -} - -// Path: skills.education.course -class _TranslationsSkillsEducationCourseEs { - _TranslationsSkillsEducationCourseEs._(this._root); - - final Translations _root; // ignore: unused_field - - // Translations - String get name => 'Ingeniería de Datos'; - String get institution => 'SEE'; - String date({required Object startDate, required Object endDate}) => '${startDate} hasta ${endDate}'; - String get description => 'Arquitectura de Datos\nModelado y Diseño de Datos\nProcesamiento Analítico\nCalidad de Datos\nProcesamiento de Big Data con Apache Spark\nTuberías de Datos con Apache Airflow'; -} - // Path: class _TranslationsEn implements Translations { /// You can call this constructor and build your own translation instance of this locale. @@ -531,11 +350,9 @@ class _TranslationsEn implements Translations { // Translations @override late final _TranslationsAboutEn about = _TranslationsAboutEn._(_root); - @override late final _TranslationsExtracurricularEn extracurricular = _TranslationsExtracurricularEn._(_root); @override late final _TranslationsProjectEn project = _TranslationsProjectEn._(_root); - @override late final _TranslationsSkillsEn skills = _TranslationsSkillsEn._(_root); @override late final _TranslationsTabsEn tabs = _TranslationsTabsEn._(_root); - @override late final _TranslationsVolunteeringEn volunteering = _TranslationsVolunteeringEn._(_root); + @override late final _TranslationsTechnologiesEn technologies = _TranslationsTechnologiesEn._(_root); } // Path: about @@ -550,18 +367,6 @@ class _TranslationsAboutEn implements _TranslationsAboutEs { @override String get presentation => 'I aspire to be a person capable of motivating, leading and teaching others. I am interested in backend development and open to learning from different areas that I can specialize in. I enjoy being involved in community and diversified learning activities. Also, in my free time I dedicate myself to develop personal projects.'; } -// Path: extracurricular -class _TranslationsExtracurricularEn implements _TranslationsExtracurricularEs { - _TranslationsExtracurricularEn._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override late final _TranslationsExtracurricularAct1En act1 = _TranslationsExtracurricularAct1En._(_root); - @override late final _TranslationsExtracurricularAct2En act2 = _TranslationsExtracurricularAct2En._(_root); - @override late final _TranslationsExtracurricularAct3En act3 = _TranslationsExtracurricularAct3En._(_root); -} - // Path: project class _TranslationsProjectEn implements _TranslationsProjectEs { _TranslationsProjectEn._(this._root); @@ -578,31 +383,6 @@ class _TranslationsProjectEn implements _TranslationsProjectEs { @override late final _TranslationsProjectSnakeGameEn snakeGame = _TranslationsProjectSnakeGameEn._(_root); } -// Path: skills -class _TranslationsSkillsEn implements _TranslationsSkillsEs { - _TranslationsSkillsEn._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override late final _TranslationsSkillsHeadersEn headers = _TranslationsSkillsHeadersEn._(_root); - @override late final _TranslationsSkillsEducationEn education = _TranslationsSkillsEducationEn._(_root); - @override List get softskills => [ - 'Teamwork', - 'Leadership', - 'Adaptability', - 'Problem Solving', - 'Critical Thinking', - 'Empathy', - 'Project Management', - 'Results Oriented', - ]; - @override List get languages => [ - 'Spanish', - 'English', - ]; -} - // Path: tabs class _TranslationsTabsEn implements _TranslationsTabsEs { _TranslationsTabsEn._(this._root); @@ -611,62 +391,21 @@ class _TranslationsTabsEn implements _TranslationsTabsEs { // Translations @override String get about => 'About'; - @override String get skills => 'Skills'; + @override String get technologies => 'Technologies'; @override String get projects => 'Projects'; - @override String get extracurricular => 'Extracurricular'; - @override String get volunteering => 'Volunteering'; -} - -// Path: volunteering -class _TranslationsVolunteeringEn implements _TranslationsVolunteeringEs { - _TranslationsVolunteeringEn._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override late final _TranslationsVolunteeringVol1En vol1 = _TranslationsVolunteeringVol1En._(_root); - @override late final _TranslationsVolunteeringVol2En vol2 = _TranslationsVolunteeringVol2En._(_root); - @override late final _TranslationsVolunteeringVol3En vol3 = _TranslationsVolunteeringVol3En._(_root); - @override late final _TranslationsVolunteeringVol4En vol4 = _TranslationsVolunteeringVol4En._(_root); } -// Path: extracurricular.act1 -class _TranslationsExtracurricularAct1En implements _TranslationsExtracurricularAct1Es { - _TranslationsExtracurricularAct1En._(this._root); +// Path: technologies +class _TranslationsTechnologiesEn implements _TranslationsTechnologiesEs { + _TranslationsTechnologiesEn._(this._root); @override final _TranslationsEn _root; // ignore: unused_field // Translations - @override String get name => ' Vol. I'; - @override String get institution => 'Guayaquil Tech'; - @override String date({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - @override String get description => 'Participation in the programming competition in a challenge proposed by the company Publifyer, contributing to the development of our project\'s API, which consumed services from OpenAI.'; -} - -// Path: extracurricular.act2 -class _TranslationsExtracurricularAct2En implements _TranslationsExtracurricularAct2Es { - _TranslationsExtracurricularAct2En._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override String get name => 'NASA Space Apps Challenge Guayaquil 2023'; - @override String get institution => 'CORPCITI'; - @override String date({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - @override String get description => 'Leader and participant in the local programming competition Space Apps in the challenge \'Planetary Tourism Office\', designing the frontend interface.'; -} - -// Path: extracurricular.act3 -class _TranslationsExtracurricularAct3En implements _TranslationsExtracurricularAct3Es { - _TranslationsExtracurricularAct3En._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override String get name => 'IOT&AI Latin America Competition 2023'; - @override String get institution => 'IEEE TEMS'; - @override String date({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - @override String get description => 'Design of the frontend interface for the project \'CrimeBuster\', which consists of a real-time crime detection system using artificial intelligence and machine learning.'; + @override String get languages => 'Languages'; + @override String get frameworks => 'Frameworks'; + @override String get databases => 'Data Bases'; + @override String get tools => 'Tools'; } // Path: project.snowNotepad @@ -787,107 +526,6 @@ class _TranslationsProjectSnakeGameEn implements _TranslationsProjectSnakeGameEs ]; } -// Path: skills.headers -class _TranslationsSkillsHeadersEn implements _TranslationsSkillsHeadersEs { - _TranslationsSkillsHeadersEn._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override String get education => 'Education'; - @override String get softskills => 'Soft Skills'; - @override String get languages => 'Languages'; -} - -// Path: skills.education -class _TranslationsSkillsEducationEn implements _TranslationsSkillsEducationEs { - _TranslationsSkillsEducationEn._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override late final _TranslationsSkillsEducationUniversityEn university = _TranslationsSkillsEducationUniversityEn._(_root); - @override late final _TranslationsSkillsEducationCourseEn course = _TranslationsSkillsEducationCourseEn._(_root); -} - -// Path: volunteering.vol1 -class _TranslationsVolunteeringVol1En implements _TranslationsVolunteeringVol1Es { - _TranslationsVolunteeringVol1En._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override String get name => 'Vice President'; - @override String get institution => 'IEEE ESPOL Computer Society'; - @override String date({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - @override String get description => 'Project management, communication with students.'; -} - -// Path: volunteering.vol2 -class _TranslationsVolunteeringVol2En implements _TranslationsVolunteeringVol2Es { - _TranslationsVolunteeringVol2En._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override String get name => 'Contributor in the 12th edition of PyWeekend 2023'; - @override String get institution => 'ESPOL'; - @override String date({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - @override String get description => 'Contributed to the development of the semifinal challenge of the Python programming competition. Also, helped guide participants on the day of the competition.'; -} - -// Path: volunteering.vol3 -class _TranslationsVolunteeringVol3En implements _TranslationsVolunteeringVol3Es { - _TranslationsVolunteeringVol3En._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override String get name => 'Guide at Django Girls'; - @override String get institution => 'Open Lab'; - @override String date({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - @override String get description => 'Contributed to ensure that participants successfully complete the introductory Django tutorial.'; -} - -// Path: volunteering.vol4 -class _TranslationsVolunteeringVol4En implements _TranslationsVolunteeringVol4Es { - _TranslationsVolunteeringVol4En._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override String get name => 'Contributor in the 2nd edition of PyTime IoT'; - @override String get institution => 'Niot ESPOL'; - @override String date({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - @override String get description => 'Provided support to students in topics related to the Python programming language and resolved their inquiries during their learning process.'; -} - -// Path: skills.education.university -class _TranslationsSkillsEducationUniversityEn implements _TranslationsSkillsEducationUniversityEs { - _TranslationsSkillsEducationUniversityEn._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override String get name => 'Computer Science Engineering'; - @override String get institution => 'ESPOL'; - @override String date({required Object startDate}) => '${startDate} to Present'; - @override String get description => '4th semester'; -} - -// Path: skills.education.course -class _TranslationsSkillsEducationCourseEn implements _TranslationsSkillsEducationCourseEs { - _TranslationsSkillsEducationCourseEn._(this._root); - - @override final _TranslationsEn _root; // ignore: unused_field - - // Translations - @override String get name => 'Data Engineering'; - @override String get institution => 'SEE'; - @override String date({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - @override String get description => 'Data Architecture\nData Modeling and Design\nAnalytical Processing\nData Quality\nBig Data Processing with Apache Spark\nData Pipelines with Apache Airflow'; -} - /// Flat map(s) containing all translations. /// Only for edge cases! For simple maps, use the map function of this library. @@ -897,18 +535,6 @@ extension on Translations { case 'about.gretting': return '¡Bienvenido, usuario desconocido!'; case 'about.title': return 'Desarrollador de Software'; case 'about.presentation': return 'Aspiro a ser una persona capaz de motivar, liderar y enseñar a los demás. Estoy interesado en el desarrollo backend y abierto a aprender de las distintas áreas en las que pueda especializarme. Me gusta involucrarme en actividades comunitarias y de aprendizaje diversificado. Además, en mis tiempos libres me dedico a desarrollar proyectos personales.'; - case 'extracurricular.act1.name': return ' Vol. I'; - case 'extracurricular.act1.institution': return 'Guayaquil Tech'; - case 'extracurricular.act1.date': return ({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - case 'extracurricular.act1.description': return 'Participación en la competencia de programación en un desafío propuesto por la empresa Publifyer, contribuyendo al desarrollo de la API de nuestro proyecto, misma que consumía los servicios de OpenAI.'; - case 'extracurricular.act2.name': return 'NASA Space Apps Challenge Guayaquil 2023'; - case 'extracurricular.act2.institution': return 'CORPCITI'; - case 'extracurricular.act2.date': return ({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - case 'extracurricular.act2.description': return 'Líder y participante en la competencia de programación local Space Apps en el desafío “Planetary Tourism Office”, diseñando la interfaz frontend.'; - case 'extracurricular.act3.name': return 'Concurso IOT&AI Latinoamérica 2023'; - case 'extracurricular.act3.institution': return 'IEEE TEMS'; - case 'extracurricular.act3.date': return ({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - case 'extracurricular.act3.description': return 'Diseño de la interfaz frontend para el proyecto “CrimeBuster”, el cual consiste en un sistema de detección de crímenes en tiempo real, utilizando inteligencia artificial y aprendizaje automático.'; case 'project.snowNotepad.title': return 'Snow Notepad'; case 'project.snowNotepad.description': return 'Un bloc de notas móvil desarrollado en Flutter, utilizando SQLite para la administración de las notas del usuario directamente en su dispositivo y sin conexión a internet.'; case 'project.snowNotepad.image': return ({required Object imagePath}) => '${imagePath}'; @@ -950,48 +576,13 @@ extension on Translations { case 'project.snakeGame.image': return ({required Object imagePath}) => '${imagePath}'; case 'project.snakeGame.repository': return ({required Object repository}) => '${repository}'; case 'project.snakeGame.technologies.0': return 'java'; - case 'skills.headers.education': return 'Educación'; - case 'skills.headers.softskills': return 'Habilidades Blandas'; - case 'skills.headers.languages': return 'Idiomas'; - case 'skills.education.university.name': return 'Ingeniería en Ciencias de la Computación'; - case 'skills.education.university.institution': return 'ESPOL'; - case 'skills.education.university.date': return ({required Object startDate}) => '${startDate} hasta la actualidad'; - case 'skills.education.university.description': return '4to semestre'; - case 'skills.education.course.name': return 'Ingeniería de Datos'; - case 'skills.education.course.institution': return 'SEE'; - case 'skills.education.course.date': return ({required Object startDate, required Object endDate}) => '${startDate} hasta ${endDate}'; - case 'skills.education.course.description': return 'Arquitectura de Datos\nModelado y Diseño de Datos\nProcesamiento Analítico\nCalidad de Datos\nProcesamiento de Big Data con Apache Spark\nTuberías de Datos con Apache Airflow'; - case 'skills.softskills.0': return 'Trabajo en Equipo'; - case 'skills.softskills.1': return 'Liderazgo'; - case 'skills.softskills.2': return 'Adaptabilidad'; - case 'skills.softskills.3': return 'Resolución de Problemas'; - case 'skills.softskills.4': return 'Pensamiento Crítico'; - case 'skills.softskills.5': return 'Empatía'; - case 'skills.softskills.6': return 'Gestión de Proyectos'; - case 'skills.softskills.7': return 'Orientado a Resultados'; - case 'skills.languages.0': return 'Español'; - case 'skills.languages.1': return 'Inglés'; case 'tabs.about': return 'Sobre mí'; - case 'tabs.skills': return 'Habilidades'; + case 'tabs.technologies': return 'Tecnologías'; case 'tabs.projects': return 'Proyectos'; - case 'tabs.extracurricular': return 'Extracurriculares'; - case 'tabs.volunteering': return 'Voluntariado'; - case 'volunteering.vol1.name': return 'Vicepresidente'; - case 'volunteering.vol1.institution': return 'IEEE ESPOL Computer Society'; - case 'volunteering.vol1.date': return ({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - case 'volunteering.vol1.description': return 'Dirección de proyectos, comunicación con estudiantes.'; - case 'volunteering.vol2.name': return 'Colaborador en la 12va edición de PyWeekend 2023'; - case 'volunteering.vol2.institution': return 'ESPOL'; - case 'volunteering.vol2.date': return ({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - case 'volunteering.vol2.description': return 'Contribuí en la elaboración del desafío de la semifinal de la competencia de programación en Python. Además, ayudé a orientar a los participantes el día de la competencia.'; - case 'volunteering.vol3.name': return 'Guía en Django Girls'; - case 'volunteering.vol3.institution': return 'Open Lab'; - case 'volunteering.vol3.date': return ({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - case 'volunteering.vol3.description': return 'Contribuí a que las participantes puedan desarrollar, satisfactoriamente, el tutorial introductorio a Django.'; - case 'volunteering.vol4.name': return 'Colaborador en la 2da edición de PyTime IoT'; - case 'volunteering.vol4.institution': return 'Niot ESPOL'; - case 'volunteering.vol4.date': return ({required Object startDate, required Object endDate}) => '${startDate} a ${endDate}'; - case 'volunteering.vol4.description': return 'Dar soporte a los estudiantes en temas relacionados al lenguaje de programación Python y resolver sus inquietudes durante su proceso de aprendizaje.'; + case 'technologies.languages': return 'Lenguajes'; + case 'technologies.frameworks': return 'Marcos de Trabajo'; + case 'technologies.databases': return 'Bases de Datos'; + case 'technologies.tools': return 'Herramientas'; default: return null; } } @@ -1003,18 +594,6 @@ extension on _TranslationsEn { case 'about.gretting': return 'Welcome, unknown user!'; case 'about.title': return 'Software Developer'; case 'about.presentation': return 'I aspire to be a person capable of motivating, leading and teaching others. I am interested in backend development and open to learning from different areas that I can specialize in. I enjoy being involved in community and diversified learning activities. Also, in my free time I dedicate myself to develop personal projects.'; - case 'extracurricular.act1.name': return ' Vol. I'; - case 'extracurricular.act1.institution': return 'Guayaquil Tech'; - case 'extracurricular.act1.date': return ({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - case 'extracurricular.act1.description': return 'Participation in the programming competition in a challenge proposed by the company Publifyer, contributing to the development of our project\'s API, which consumed services from OpenAI.'; - case 'extracurricular.act2.name': return 'NASA Space Apps Challenge Guayaquil 2023'; - case 'extracurricular.act2.institution': return 'CORPCITI'; - case 'extracurricular.act2.date': return ({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - case 'extracurricular.act2.description': return 'Leader and participant in the local programming competition Space Apps in the challenge \'Planetary Tourism Office\', designing the frontend interface.'; - case 'extracurricular.act3.name': return 'IOT&AI Latin America Competition 2023'; - case 'extracurricular.act3.institution': return 'IEEE TEMS'; - case 'extracurricular.act3.date': return ({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - case 'extracurricular.act3.description': return 'Design of the frontend interface for the project \'CrimeBuster\', which consists of a real-time crime detection system using artificial intelligence and machine learning.'; case 'project.snowNotepad.title': return 'Snow Notepad'; case 'project.snowNotepad.description': return 'A mobile notepad developed in Flutter, using SQLite for managing user notes directly on their device and offline.'; case 'project.snowNotepad.image': return ({required Object imagePath}) => '${imagePath}'; @@ -1056,48 +635,13 @@ extension on _TranslationsEn { case 'project.snakeGame.image': return ({required Object imagePath}) => '${imagePath}'; case 'project.snakeGame.repository': return ({required Object repository}) => '${repository}'; case 'project.snakeGame.technologies.0': return 'java'; - case 'skills.headers.education': return 'Education'; - case 'skills.headers.softskills': return 'Soft Skills'; - case 'skills.headers.languages': return 'Languages'; - case 'skills.education.university.name': return 'Computer Science Engineering'; - case 'skills.education.university.institution': return 'ESPOL'; - case 'skills.education.university.date': return ({required Object startDate}) => '${startDate} to Present'; - case 'skills.education.university.description': return '4th semester'; - case 'skills.education.course.name': return 'Data Engineering'; - case 'skills.education.course.institution': return 'SEE'; - case 'skills.education.course.date': return ({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - case 'skills.education.course.description': return 'Data Architecture\nData Modeling and Design\nAnalytical Processing\nData Quality\nBig Data Processing with Apache Spark\nData Pipelines with Apache Airflow'; - case 'skills.softskills.0': return 'Teamwork'; - case 'skills.softskills.1': return 'Leadership'; - case 'skills.softskills.2': return 'Adaptability'; - case 'skills.softskills.3': return 'Problem Solving'; - case 'skills.softskills.4': return 'Critical Thinking'; - case 'skills.softskills.5': return 'Empathy'; - case 'skills.softskills.6': return 'Project Management'; - case 'skills.softskills.7': return 'Results Oriented'; - case 'skills.languages.0': return 'Spanish'; - case 'skills.languages.1': return 'English'; case 'tabs.about': return 'About'; - case 'tabs.skills': return 'Skills'; + case 'tabs.technologies': return 'Technologies'; case 'tabs.projects': return 'Projects'; - case 'tabs.extracurricular': return 'Extracurricular'; - case 'tabs.volunteering': return 'Volunteering'; - case 'volunteering.vol1.name': return 'Vice President'; - case 'volunteering.vol1.institution': return 'IEEE ESPOL Computer Society'; - case 'volunteering.vol1.date': return ({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - case 'volunteering.vol1.description': return 'Project management, communication with students.'; - case 'volunteering.vol2.name': return 'Contributor in the 12th edition of PyWeekend 2023'; - case 'volunteering.vol2.institution': return 'ESPOL'; - case 'volunteering.vol2.date': return ({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - case 'volunteering.vol2.description': return 'Contributed to the development of the semifinal challenge of the Python programming competition. Also, helped guide participants on the day of the competition.'; - case 'volunteering.vol3.name': return 'Guide at Django Girls'; - case 'volunteering.vol3.institution': return 'Open Lab'; - case 'volunteering.vol3.date': return ({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - case 'volunteering.vol3.description': return 'Contributed to ensure that participants successfully complete the introductory Django tutorial.'; - case 'volunteering.vol4.name': return 'Contributor in the 2nd edition of PyTime IoT'; - case 'volunteering.vol4.institution': return 'Niot ESPOL'; - case 'volunteering.vol4.date': return ({required Object startDate, required Object endDate}) => '${startDate} to ${endDate}'; - case 'volunteering.vol4.description': return 'Provided support to students in topics related to the Python programming language and resolved their inquiries during their learning process.'; + case 'technologies.languages': return 'Languages'; + case 'technologies.frameworks': return 'Frameworks'; + case 'technologies.databases': return 'Data Bases'; + case 'technologies.tools': return 'Tools'; default: return null; } } diff --git a/snow_portfolio/lib/main.dart b/snow_portfolio/lib/main.dart index 582069c..b0dbc3a 100644 --- a/snow_portfolio/lib/main.dart +++ b/snow_portfolio/lib/main.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:snow_portfolio/config/config.dart'; - +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:snow_portfolio/presentation/bloc/bloc.dart'; import 'generated/translations.g.dart'; void main() async { @@ -11,29 +11,51 @@ void main() async { LocaleSettings.useDeviceLocale(); Intl.defaultLocale = WidgetsBinding.instance.platformDispatcher.locale.languageCode; - runApp(TranslationProvider(child: const Main())); + + runApp( + MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => HomeCubit(), + ), + BlocProvider( + create: (context) => AboutMeCubit(), + ), + BlocProvider( + create: (context) => TechnologiesCubit(), + ), + BlocProvider( + create: (context) => ProjectsCubit(), + ), + ], + child: TranslationProvider( + child: const MainPage(), + ), + ), + ); } -class Main extends StatelessWidget { - const Main({super.key}); +class MainPage extends StatelessWidget { + const MainPage({super.key}); @override Widget build(BuildContext context) { - return GetMaterialApp( - title: 'Alexander Portfolio', + var homeState = context.watch().state; + + return MaterialApp.router( + title: 'Alexander Nieves Portfolio', localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], supportedLocales: AppLocaleUtils.supportedLocales, - locale: TranslationProvider.of(context).flutterLocale, + locale: homeState.currentLocale.flutterLocale, theme: PortfolioTheme().themeData, darkTheme: PortfolioTheme(useDarkMode: true).themeData, - initialRoute: AppPages.INITIAL, - getPages: AppPages.routes, + themeMode: homeState.themeMode, debugShowCheckedModeBanner: false, - initialBinding: BindingsBuilders.bindings, + routerConfig: AppPages.router, ); } } diff --git a/snow_portfolio/lib/presentation/controllers/about_me/about_me_controller.dart b/snow_portfolio/lib/presentation/bloc/about_me/about_me_cubit.dart similarity index 50% rename from snow_portfolio/lib/presentation/controllers/about_me/about_me_controller.dart rename to snow_portfolio/lib/presentation/bloc/about_me/about_me_cubit.dart index 9016d18..b4b4ac0 100644 --- a/snow_portfolio/lib/presentation/controllers/about_me/about_me_controller.dart +++ b/snow_portfolio/lib/presentation/bloc/about_me/about_me_cubit.dart @@ -1,25 +1,19 @@ -import 'package:get/get.dart'; +import 'package:bloc/bloc.dart'; + import '../../../generated/translations.g.dart'; -class AboutMeController extends GetxController { +part 'about_me_state.dart'; + +class AboutMeCubit extends Cubit { + AboutMeCubit() : super(AboutMeState()); + + final name = 'Geovanny Alexander\nNieves Reyes'; - final softwareTechnologies = [ - 'dart', - 'java', - 'python', - 'flutter', - 'springboot', - 'mysql', - 'postgresql', - 'sql server', - 'git', - ]; String get presentation => texts.about.presentation; String get title => texts.about.title; String get gretting => texts.about.gretting; - } diff --git a/snow_portfolio/lib/presentation/bloc/about_me/about_me_state.dart b/snow_portfolio/lib/presentation/bloc/about_me/about_me_state.dart new file mode 100644 index 0000000..e86d99a --- /dev/null +++ b/snow_portfolio/lib/presentation/bloc/about_me/about_me_state.dart @@ -0,0 +1,3 @@ +part of 'about_me_cubit.dart'; + +final class AboutMeState {} diff --git a/snow_portfolio/lib/presentation/bloc/bloc.dart b/snow_portfolio/lib/presentation/bloc/bloc.dart new file mode 100644 index 0000000..7c6b7d9 --- /dev/null +++ b/snow_portfolio/lib/presentation/bloc/bloc.dart @@ -0,0 +1,4 @@ +export 'about_me/about_me_cubit.dart'; +export 'projects/projects_cubit.dart'; +export 'technologies/technologies_cubit.dart'; +export 'home/home_cubit.dart'; diff --git a/snow_portfolio/lib/presentation/bloc/home/home_cubit.dart b/snow_portfolio/lib/presentation/bloc/home/home_cubit.dart new file mode 100644 index 0000000..b0e7f50 --- /dev/null +++ b/snow_portfolio/lib/presentation/bloc/home/home_cubit.dart @@ -0,0 +1,82 @@ +import 'package:bloc/bloc.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:snow_portfolio/config/config.dart'; + +import '../../../generated/translations.g.dart'; + +part 'home_state.dart'; + +class HomeCubit extends Cubit { + HomeCubit() + : super(HomeState( + themeMode: ThemeMode.system, + currentLocale: LocaleSettings.currentLocale, + )); + + final String email = 'alexitosnow2002@gmail.com'; + final String phone = '+593983678577'; + + List get pages => [ + Pages( + title: texts.tabs.about, + route: Routes.ABOUT, + ), + Pages( + title: texts.tabs.technologies, + route: Routes.TECHNOLOGIES, + ), + Pages( + title: texts.tabs.projects, + route: Routes.PROJECTS, + ), + ]; + + AppLocale get es => AppLocale.es; + + AppLocale get en => AppLocale.en; + + void switchTheme(Brightness brightness) { + emit(HomeState( + currentPage: state.currentPage, + currentLocale: state.currentLocale, + themeMode: + brightness == Brightness.dark ? ThemeMode.light : ThemeMode.dark, + )); + } + + void changePage(int index) { + emit(HomeState( + currentPage: index, + themeMode: state.themeMode, + currentLocale: state.currentLocale)); + AppPages.router.goNamed(pages[index].route); + } + + String? encodeQueryParameters(Map params) { + return params.entries + .map((MapEntry e) => + '${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}') + .join('&'); + } + + void changeLocale(AppLocale locale) { + Intl.defaultLocale = locale.languageCode; + LocaleSettings.setLocale(locale); + emit(HomeState( + currentPage: state.currentPage, + themeMode: state.themeMode, + currentLocale: locale, + )); + } +} + +class Pages { + String title; + String route; + + Pages({ + required this.title, + required this.route, + }); +} diff --git a/snow_portfolio/lib/presentation/bloc/home/home_state.dart b/snow_portfolio/lib/presentation/bloc/home/home_state.dart new file mode 100644 index 0000000..3c50a6a --- /dev/null +++ b/snow_portfolio/lib/presentation/bloc/home/home_state.dart @@ -0,0 +1,12 @@ +part of 'home_cubit.dart'; + +final class HomeState { + int currentPage; + ThemeMode themeMode; + AppLocale currentLocale; + HomeState({ + this.currentPage = 0, + required this.themeMode, + required this.currentLocale, + }); +} diff --git a/snow_portfolio/lib/presentation/bloc/projects/projects_cubit.dart b/snow_portfolio/lib/presentation/bloc/projects/projects_cubit.dart new file mode 100644 index 0000000..9a46f70 --- /dev/null +++ b/snow_portfolio/lib/presentation/bloc/projects/projects_cubit.dart @@ -0,0 +1,20 @@ +import 'package:bloc/bloc.dart'; +import 'package:flutter/material.dart'; + +import '../../../domain/models.dart'; + +part 'projects_state.dart'; + +class ProjectsCubit extends Cubit { + ProjectsCubit() : super(ProjectsState()); + + ScrollController scrollController = ScrollController(); + List get projectItems => Project.projectItems; + PageController pageController = PageController(keepPage: true); + int currentPage = 0; + + void onHover(int index, bool isHovering) { + var hIndex = isHovering ? index : -1; + emit(ProjectsState(hoveringIndex: hIndex)); + } +} diff --git a/snow_portfolio/lib/presentation/bloc/projects/projects_state.dart b/snow_portfolio/lib/presentation/bloc/projects/projects_state.dart new file mode 100644 index 0000000..d6a70db --- /dev/null +++ b/snow_portfolio/lib/presentation/bloc/projects/projects_state.dart @@ -0,0 +1,8 @@ +part of 'projects_cubit.dart'; + +final class ProjectsState { + final int hoveringIndex; + ProjectsState({ + this.hoveringIndex = -1, + }); +} diff --git a/snow_portfolio/lib/presentation/bloc/technologies/technologies_cubit.dart b/snow_portfolio/lib/presentation/bloc/technologies/technologies_cubit.dart new file mode 100644 index 0000000..e500fa5 --- /dev/null +++ b/snow_portfolio/lib/presentation/bloc/technologies/technologies_cubit.dart @@ -0,0 +1,40 @@ +import 'package:bloc/bloc.dart'; +import 'package:snow_portfolio/generated/translations.g.dart'; + +part 'technologies_state.dart'; + +class TechnologiesCubit extends Cubit { + TechnologiesCubit() : super(TechnologiesState()); + + String get languagesText => texts.technologies.languages; + + String get frameworksText => texts.technologies.frameworks; + + String get databasesText => texts.technologies.databases; + + String get toolsText => texts.technologies.tools; + + final languages = [ + 'dart', + 'java', + 'python', + ]; + + final databases = [ + 'mysql', + 'postgresql', + 'sql server', + 'firebase', + ]; + + final frameworks = [ + 'flutter', + 'springboot', + ]; + + final tools = [ + 'git', + 'github', + 'visual studio code', + ]; +} diff --git a/snow_portfolio/lib/presentation/bloc/technologies/technologies_state.dart b/snow_portfolio/lib/presentation/bloc/technologies/technologies_state.dart new file mode 100644 index 0000000..a874224 --- /dev/null +++ b/snow_portfolio/lib/presentation/bloc/technologies/technologies_state.dart @@ -0,0 +1,3 @@ +part of 'technologies_cubit.dart'; + +final class TechnologiesState {} \ No newline at end of file diff --git a/snow_portfolio/lib/presentation/controllers/controllers.dart b/snow_portfolio/lib/presentation/controllers/controllers.dart deleted file mode 100644 index 19ce4e9..0000000 --- a/snow_portfolio/lib/presentation/controllers/controllers.dart +++ /dev/null @@ -1,6 +0,0 @@ -export 'about_me/about_me_controller.dart'; -export 'extracurricular/extracurricular_controller.dart'; -export 'home/home_controller.dart'; -export 'projects/projects_controller.dart'; -export 'skills/skills_controller.dart'; -export 'volunteering/volunteering_controller.dart'; \ No newline at end of file diff --git a/snow_portfolio/lib/presentation/controllers/extracurricular/extracurricular_controller.dart b/snow_portfolio/lib/presentation/controllers/extracurricular/extracurricular_controller.dart deleted file mode 100644 index e9cdd9b..0000000 --- a/snow_portfolio/lib/presentation/controllers/extracurricular/extracurricular_controller.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:get/get.dart'; -import '../../../generated/translations.g.dart'; -import '../../../domain/models/extracurricular_model.dart'; -import '../../../config/utils/constants.dart'; - -class ExtracurricularController extends GetxController { - get _extra => texts.extracurricular; - - List get extracurricularList => [ - Extracurricular( - name: _extra.act1.name, - institution: _extra.act1.institution, - date: _extra.act1.date( - startDate: dateFormatter(DateTime(2023, 7, 8)), - endDate: dateFormatter(DateTime(2024, 7, 9)), - ), - description: _extra.act1.description, - ), - Extracurricular( - name: _extra.act2.name, - institution: _extra.act2.institution, - date: _extra.act2.date( - startDate: dateFormatter(DateTime(2023, 10, 7)), - endDate: dateFormatter(DateTime(2023, 10, 8)), - ), - description: _extra.act2.description, - ), - Extracurricular( - name: _extra.act3.name, - institution: _extra.act3.institution, - date: _extra.act3.date( - startDate: dateFormatter(DateTime(2023, 8, 1)), - endDate: dateFormatter(DateTime(2023, 10, 20)), - ), - description: _extra.act3.description, - ), - ]; -} diff --git a/snow_portfolio/lib/presentation/controllers/home/home_controller.dart b/snow_portfolio/lib/presentation/controllers/home/home_controller.dart deleted file mode 100644 index 51a0df2..0000000 --- a/snow_portfolio/lib/presentation/controllers/home/home_controller.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:intl/intl.dart'; -import 'package:scrollable_positioned_list/scrollable_positioned_list.dart' - show ItemScrollController; -import '../../../generated/translations.g.dart'; -import '../../screens/about_me/about_me_view.dart'; -import '../../screens/extracurricular/extracurricular_view.dart'; -import '../../screens/projects/projects_view.dart'; -import '../../screens/skills/skills_view.dart'; -import '../../screens/volunteering/volunteering_view.dart'; - -class HomeController extends GetxController - with GetSingleTickerProviderStateMixin { - final String email = 'alexitosnow2002@gmail.com'; - final String phone = '+593 98 367 8577'; - final line = 'Hi Alexander, I would like to contact you'; - final _isDark = false.obs; - - final RxInt _currentPage = 0.obs; - - final itemScrollController = ItemScrollController(); - - int get currentPage => _currentPage.value; - - set currentPage(int value) => _currentPage.value = value; - - bool get isDark { - return _isDark.value; - } - - AppLocale get es => AppLocale.es; - - AppLocale get en => AppLocale.en; - - AppLocale get currentLocale => LocaleSettings.currentLocale; - - List
get headers => [ - Header( - title: texts.tabs.about, - page: const AboutMeView(), - icon: const Icon(Icons.person), - ), - Header( - title: texts.tabs.skills, - page: const SkillsView(), - icon: const Icon(Icons.school), - ), - Header( - title: texts.tabs.projects, - page: const ProjectsView(), - icon: const Icon(Icons.work), - ), - Header( - title: texts.tabs.extracurricular, - page: const ExtracurricularView(), - icon: const Icon(Icons.star), - ), - Header( - title: texts.tabs.volunteering, - page: const VolunteeringView(), - icon: const Icon(Icons.favorite), - ), - ]; - - List get titles => headers.map((e) => e.title).toList(); - - List get pages => headers.map((e) => e.page).toList(); - - List get icons => headers.map((e) => e.icon).toList(); - - void changePage(int index) { - itemScrollController.scrollTo( - index: index, - duration: const Duration(seconds: 1), - curve: Curves.easeIn, - ); - currentPage = index; - } - - String? encodeQueryParameters(Map params) { - return params.entries - .map((MapEntry e) => - '${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}') - .join('&'); - } - - void changeTheme() { - Get.changeThemeMode( - Get.isDarkMode ? ThemeMode.light : ThemeMode.dark, - ); - _isDark.toggle(); - } - - void changeLocale(AppLocale code) { - LocaleSettings.setLocale(code); - Intl.defaultLocale = code.languageCode; - Get.updateLocale(Locale(code.languageCode)); - } -} - -class Header { - String title; - Widget page; - Widget icon; - - Header({ - required this.title, - required this.page, - required this.icon, - }); -} diff --git a/snow_portfolio/lib/presentation/controllers/projects/projects_controller.dart b/snow_portfolio/lib/presentation/controllers/projects/projects_controller.dart deleted file mode 100644 index d68025d..0000000 --- a/snow_portfolio/lib/presentation/controllers/projects/projects_controller.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:get/get.dart'; - -import '../../../generated/translations.g.dart'; -import '../../../domain/models/project_model.dart'; - -class ProjectsController extends GetxController { - List get projectItems => [ - Project( - title: texts.project.snowNotepad.title, - description: texts.project.snowNotepad.description, - image: texts.project.snowNotepad.image(imagePath: '$imagePath/snownotepad_project.jpg'), - repository: texts.project.snowNotepad.repository(repository: '$github/SnowNotepad'), - technologies: texts.project.snowNotepad.technologies, - ), - Project( - title: texts.project.crimeBuster.title, - description: texts.project.crimeBuster.description, - image: texts.project.crimeBuster.image(imagePath: '$imagePath/crimebuster_project.jpg'), - repository: texts.project.crimeBuster.repository(repository: '$github/CrimeBuster-IoTEngine'), - technologies: texts.project.crimeBuster.technologies, - ), - Project( - title: texts.project.polaris.title, - description: texts.project.polaris.description, - image: texts.project.polaris.image(imagePath: '$imagePath/polaris_project.png'), - repository: texts.project.polaris.repository(repository: '$github/proyect_polaris'), - technologies: texts.project.polaris.technologies, - ), - Project( - title: texts.project.notepadWeb.title, - description: texts.project.notepadWeb.description, - image: texts.project.notepadWeb.image(imagePath: '$imagePath/notepad_web_project.jpg'), - repository: texts.project.notepadWeb.repository(repository: '$github/notepad_web_app'), - technologies: texts.project.notepadWeb.technologies, - ), - Project( - title: texts.project.notepadAPI.title, - description: texts.project.notepadAPI.description, - image: texts.project.notepadAPI.image(imagePath: '$imagePath/notepad_api_project.png'), - repository: texts.project.notepadAPI.repository(repository: '$github/notepad_api'), - technologies: texts.project.notepadAPI.technologies, - ), - Project( - title: texts.project.chasing30.title, - description: texts.project.chasing30.description, - image: texts.project.chasing30.image(imagePath: '$imagePath/chasing30_project.png'), - repository: texts.project.chasing30.repository(repository: '$github/PyWeekend-ESPOL'), - technologies: texts.project.chasing30.technologies, - ), - Project( - title: texts.project.snakeGame.title, - description: texts.project.snakeGame.description, - image: texts.project.snakeGame.image(imagePath: '$imagePath/snake_project.jpeg'), - repository: texts.project.snakeGame.repository(repository: '$github/proyecto-aniversarioIEEE-Snake'), - technologies: texts.project.snakeGame.technologies, - ), - ]; - - List get projectNames => - projectItems.map((e) => e.title ?? '').toList(); - - List get projectDescriptions => - projectItems.map((e) => e.description ?? '').toList(); - - List get projectImages => - projectItems.map((e) => e.image ?? '').toList(); -} diff --git a/snow_portfolio/lib/presentation/controllers/skills/skills_controller.dart b/snow_portfolio/lib/presentation/controllers/skills/skills_controller.dart deleted file mode 100644 index f074df9..0000000 --- a/snow_portfolio/lib/presentation/controllers/skills/skills_controller.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:get/get.dart'; -import '../../../generated/translations.g.dart'; -import '../../../domain/models/education_model.dart'; -import '../../../config/utils/constants.dart'; - -class SkillsController extends GetxController { - get headers => texts.skills.headers; - - get university => texts.skills.education.university; - - get course => texts.skills.education.course; - - get languages => texts.skills.languages; - - get softSkills => texts.skills.softskills; - - String get educationHeader => headers.education; - - String get softSkillsHeader => headers.softskills; - - String get languagesHeader => headers.languages; - - List get education => [ - Education( - name: university.name, - institution: university.institution, - date: university.date( - startDate: dateFormatter(DateTime(2022, 5, 1)), - ), - description: university.description, - ), - Education( - name: course.name, - institution: course.institution, - date: course.date( - startDate: dateFormatter(DateTime(2023, 5, 1)), - endDate: dateFormatter(DateTime(2023, 9, 1)), - ), - description: course.description, - ), - ]; -} diff --git a/snow_portfolio/lib/presentation/controllers/volunteering/volunteering_controller.dart b/snow_portfolio/lib/presentation/controllers/volunteering/volunteering_controller.dart deleted file mode 100644 index 96560d3..0000000 --- a/snow_portfolio/lib/presentation/controllers/volunteering/volunteering_controller.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:get/get.dart'; -import '../../../generated/translations.g.dart'; -import '../../../domain/models/volunteering_model.dart'; -import '../../../config/utils/constants.dart'; - -class VolunteeringController extends GetxController { - get vol => texts.volunteering; - - List get volunteeringList => [ - Volunteering( - name: vol.vol1.name, - description: vol.vol1.description, - date: vol.vol1.date( - startDate: dateFormatter( - DateTime(2023, 1, 1), - ), - endDate: dateFormatter( - DateTime(2024, 1, 1), - ), - ), - institution: vol.vol1.institution, - ), - Volunteering( - name: vol.vol2.name, - description: vol.vol2.description, - date: vol.vol1.date( - startDate: dateFormatter( - DateTime(2023, 8, 1), - ), - endDate: dateFormatter( - DateTime(2023, 8, 30), - ), - ), - institution: vol.vol2.institution, - ), - Volunteering( - name: vol.vol3.name, - description: vol.vol3.description, - date: vol.vol1.date( - startDate: dateFormatter( - DateTime(2023, 8, 5), - ), - endDate: dateFormatter( - DateTime(2023, 8, 5), - ), - ), - institution: vol.vol3.institution, - ), - Volunteering( - name: vol.vol4.name, - description: vol.vol4.description, - date: vol.vol1.date( - startDate: dateFormatter( - DateTime(2023, 12, 1), - ), - endDate: dateFormatter( - DateTime(2023, 12, 2), - ), - ), - institution: vol.vol4.institution, - ), - ]; -} diff --git a/snow_portfolio/lib/presentation/screens/about_me/about_me_view.dart b/snow_portfolio/lib/presentation/screens/about_me/about_me_view.dart index 80f8660..08b0741 100644 --- a/snow_portfolio/lib/presentation/screens/about_me/about_me_view.dart +++ b/snow_portfolio/lib/presentation/screens/about_me/about_me_view.dart @@ -1,35 +1,30 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; -import 'package:get/get.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lottie/lottie.dart'; -import 'package:animated_text_kit/animated_text_kit.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:snow_portfolio/config/config.dart'; -import 'package:snow_portfolio/presentation/controllers/controllers.dart'; +import 'package:snow_portfolio/presentation/bloc/bloc.dart'; +import 'gretting.dart'; -class AboutMeView extends GetView { +class AboutMeView extends StatelessWidget { const AboutMeView({super.key}); @override Widget build(BuildContext context) { isPhone = context.width <= 800; + final controller = context.watch(); return ResponsiveFlex( + key: ValueKey(context.watch().state.currentLocale.toString()), children: [ - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - gretting, - name, - title, - presentation, - DevIconsList( - iconList: controller.softwareTechnologies, - ), - ], - ), - ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Gretting(), + name(controller.name), + title(controller.title), + presentation(context), + ], + ).paddingOnly(left: 8.0), Expanded( flex: 7, child: LottieBuilder.network( @@ -41,11 +36,11 @@ class AboutMeView extends GetView { ); } - Widget get presentation { + Widget presentation(BuildContext context) { + final controller = context.watch(); return SizedBox( - width: Get.width * (isPhone ? 0.8 : 0.5), + width: context.width * (isPhone ? 0.8 : 0.5), child: AutoSizeText( - key: Key(controller.presentation), controller.presentation, style: const TextStyle( fontSize: 15, @@ -57,9 +52,9 @@ class AboutMeView extends GetView { ); } - Text get title { + Text title(String title) { return Text( - controller.title, + title, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, @@ -68,9 +63,9 @@ class AboutMeView extends GetView { ); } - Text get name { + Text name(String name) { return Text( - controller.name, + name, style: const TextStyle( fontSize: 30, fontWeight: FontWeight.bold, @@ -78,24 +73,6 @@ class AboutMeView extends GetView { textAlign: TextAlign.start, ); } - - Widget get gretting { - return AnimatedTextKit( - key: Key(controller.gretting), - isRepeatingAnimation: false, - animatedTexts: [ - TypewriterAnimatedText( - controller.gretting, - textStyle: GoogleFonts.inconsolata( - textStyle: const TextStyle( - fontSize: 20, - ), - ), - speed: const Duration(milliseconds: 200), - ), - ], - ); - } } -bool isPhone = false; \ No newline at end of file +bool isPhone = false; diff --git a/snow_portfolio/lib/presentation/screens/about_me/gretting.dart b/snow_portfolio/lib/presentation/screens/about_me/gretting.dart new file mode 100644 index 0000000..a3a0ed7 --- /dev/null +++ b/snow_portfolio/lib/presentation/screens/about_me/gretting.dart @@ -0,0 +1,29 @@ +import 'package:animated_text_kit/animated_text_kit.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:snow_portfolio/presentation/bloc/bloc.dart'; + +class Gretting extends StatelessWidget { + const Gretting({super.key}); + + @override + Widget build(BuildContext context) { + final controller = context.watch(); + return AnimatedTextKit( + key: ValueKey(key), + isRepeatingAnimation: false, + animatedTexts: [ + TypewriterAnimatedText( + controller.gretting, + textStyle: GoogleFonts.inconsolata( + textStyle: const TextStyle( + fontSize: 20, + ), + ), + speed: const Duration(milliseconds: 200), + ), + ], + ); + } +} diff --git a/snow_portfolio/lib/presentation/screens/extracurricular/extracurricular_view.dart b/snow_portfolio/lib/presentation/screens/extracurricular/extracurricular_view.dart deleted file mode 100644 index 04fa5cf..0000000 --- a/snow_portfolio/lib/presentation/screens/extracurricular/extracurricular_view.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:get/get.dart'; -import 'package:lottie/lottie.dart'; -import 'package:snow_portfolio/config/config.dart'; - -import '../../controllers/controllers.dart'; - -class ExtracurricularView extends GetView { - const ExtracurricularView({super.key}); - @override - Widget build(BuildContext context) { - return ResponsiveFlex( - children: [ - Expanded( - flex: 6, - child: ActivityList(controller.extracurricularList), - ), - Expanded( - flex: 4, - child: LottieBuilder.network( - 'https://lottie.host/4a74e00f-d3be-4c87-a10a-ee3233015f03/2gbh4pwphF.json', - alignment: Alignment.centerRight, - ), - ), - ], - ); - } -} diff --git a/snow_portfolio/lib/presentation/screens/home/footer.dart b/snow_portfolio/lib/presentation/screens/home/footer.dart new file mode 100644 index 0000000..c592bcd --- /dev/null +++ b/snow_portfolio/lib/presentation/screens/home/footer.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:snow_portfolio/config/config.dart'; +import 'package:snow_portfolio/presentation/bloc/bloc.dart'; +import 'package:snow_portfolio/presentation/screens/home/social_button.dart'; + +class Footer extends StatelessWidget { + const Footer({super.key}); + + @override + Widget build(BuildContext context) { + final controller = context.read(); + return Column( + children: [ + const Divider( + thickness: 2, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('Copyright © 2024 | Alexander Nieves'), + Row( + children: [ + SocialButton( + url: Uri.parse('https://www.github.com/AlexitoSnow/'), + logo: FontAwesomeIcons.squareGithub, + tooltip: 'Alexito Snow'), + SocialButton( + url: Uri.parse( + 'https://www.linkedin.com/in/alexander-nieves/'), + logo: FontAwesomeIcons.linkedin, + tooltip: 'Alexander Nieves'), + SocialButton( + url: Uri( + scheme: 'mailto', + path: controller.email, + query: controller.encodeQueryParameters( + { + 'subject': 'Contact Info', + 'body': 'Hi Alexander, I would like to contact you', + }, + ), + ), + logo: Icons.email, + tooltip: controller.email, + ), + SocialButton( + url: Uri.parse('whatsapp://send?phone=${controller.phone}'), + logo: FontAwesomeIcons.whatsapp, + tooltip: controller.phone, + ), + ], + ), + ], + ).paddingSymmetric(horizontal: context.width * 0.01), + ], + ); + } +} diff --git a/snow_portfolio/lib/presentation/screens/home/home_view.dart b/snow_portfolio/lib/presentation/screens/home/home_view.dart index ca877ad..191cff3 100644 --- a/snow_portfolio/lib/presentation/screens/home/home_view.dart +++ b/snow_portfolio/lib/presentation/screens/home/home_view.dart @@ -1,14 +1,15 @@ import 'package:flutter/material.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'package:get/get.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:snow_portfolio/config/config.dart'; import '../../../generated/translations.g.dart'; -import '../../controllers/controllers.dart'; +import '../../bloc/bloc.dart'; +import 'footer.dart'; import 'responsive_bar.dart'; -import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; -class HomeView extends GetView { - const HomeView({super.key}); +class HomeView extends StatelessWidget { + const HomeView({super.key, required this.page}); + + final Widget page; @override Widget build(BuildContext context) { @@ -22,112 +23,55 @@ class HomeView extends GetView { elevation: 10, ), drawer: isPhone ? ResponsiveBar(isPhone) : null, - body: ScrollablePositionedList.builder( - itemScrollController: controller.itemScrollController, - itemCount: controller.pages.length + 1, - itemBuilder: (context, index) { - // Si es el último índice, retorna el Container - if (index == controller.pages.length) { - return SizedBox( - height: context.height * 0.3, - child: const Column( - children: [ - VerticalDivider( - thickness: 2, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Column( - children: [ - Text('© Geovanny Alexander Nieves Reyes 2024'), - ], - ), - ], - ), - ], - ), - ); - } - return controller.pages[index]; - }, - ), - persistentFooterButtons: isPhone ? null : contact, - ); - } - - List get actions { - return [ - socialButton( - 'https://www.github.com/AlexitoSnow/', FontAwesomeIcons.squareGithub), - socialButton('https://www.linkedin.com/in/alexander-nieves/', - FontAwesomeIcons.linkedin), - Obx( - () => IconButton( - onPressed: () { - controller.changeTheme(); - }, - icon: Icon(controller.isDark ? Icons.light_mode : Icons.dark_mode), - ), - ), - PopupMenuButton( - onSelected: (value) { - controller.changeLocale(value); - }, - icon: const Icon(Icons.translate), - itemBuilder: (_) { - return [ - PopupMenuItem( - value: controller.en, - child: const Text("English"), + body: SingleChildScrollView( + child: Column( + children: [ + IntrinsicHeight( + child: page, ), - PopupMenuItem( - value: controller.es, - child: const Text("Español"), - ), - ]; - }, + const Footer(), + ], + ).paddingOnly(left: 15, right: 15, top: 15), ), - ]; - } - - IconButton socialButton(String url, IconData logo) { - return IconButton( - onPressed: () { - launchUrl(Uri.parse(url)); - }, - icon: FaIcon(logo), ); } - List get contact { + List get actions { return [ - TextButton.icon( - icon: const Icon(Icons.email), - onPressed: () async { - final Uri emailLaunchUri = Uri( - scheme: 'mailto', - path: controller.email, - query: controller.encodeQueryParameters({ - 'subject': 'Contact Info', - 'body': controller.line, - }), + BlocBuilder( + builder: (context, state) { + final controller = context.watch(); + return Row( + children: [ + IconButton( + onPressed: () { + controller.switchTheme(Theme.of(context).brightness); + }, + icon: Icon(Theme.of(context).brightness == Brightness.dark + ? Icons.dark_mode + : Icons.light_mode), + ), + PopupMenuButton( + onSelected: (value) { + controller.changeLocale(value); + }, + icon: const Icon(Icons.translate), + itemBuilder: (_) { + return [ + PopupMenuItem( + value: controller.en, + child: const Text("English"), + ), + PopupMenuItem( + value: controller.es, + child: const Text("Español"), + ), + ]; + }, + ), + ], ); - await launchUrl(emailLaunchUri); - }, - label: Text(controller.email), - ), - TextButton.icon( - icon: const FaIcon(FontAwesomeIcons.whatsapp), - onPressed: () async { - final message = - controller.encodeQueryParameters({'text': controller.line})!; - final phone = controller.phone.replaceAll(' ', ''); - final Uri whatsappLaunchUri = - Uri.parse('whatsapp://send?phone=$phone&$message'); - await launchUrl(whatsappLaunchUri, webOnlyWindowName: '_self'); }, - label: Text(controller.phone), ), ]; } diff --git a/snow_portfolio/lib/presentation/screens/home/responsive_bar.dart b/snow_portfolio/lib/presentation/screens/home/responsive_bar.dart index 55dd03f..dcc7884 100644 --- a/snow_portfolio/lib/presentation/screens/home/responsive_bar.dart +++ b/snow_portfolio/lib/presentation/screens/home/responsive_bar.dart @@ -1,48 +1,62 @@ import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:snow_portfolio/presentation/controllers/home/home_controller.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:snow_portfolio/config/config.dart'; +import 'package:snow_portfolio/presentation/bloc/bloc.dart'; -class ResponsiveBar extends GetView { +class ResponsiveBar extends StatelessWidget { final bool isPhone; Widget get _showTopBar { - return Row( - children: List.generate( - controller.titles.length, - (index) => Obx( - () => InkWell( - onTap: () => controller.changePage(index), - child: Text( - controller.titles[index], - style: TextStyle( - decoration: controller.currentPage == index - ? TextDecoration.underline - : null), - ).paddingSymmetric(horizontal: 20), - ), - ), - )); + return BlocBuilder( + builder: (context, state) { + final controller = context.watch(); + return Row( + children: List.generate( + controller.pages.length, + (index) => InkWell( + onTap: () => controller.changePage(index), + child: AnimatedContainer( + duration: const Duration(seconds: 1), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: controller.state.currentPage == index + ? mainColor + : Colors.transparent, + ), + child: Text(controller.pages[index].title) + .paddingSymmetric(horizontal: 20), + ), + ), + ), + ); + }, + ); } Widget get _showDrawer { - return Obx( - () => NavigationDrawer( - onDestinationSelected: (int index) { - controller.changePage(index); - }, - selectedIndex: controller.currentPage, - children: [ - const Align( - alignment: Alignment.centerRight, - child: CloseButton(), - ), - for (var i = 0; i < controller.titles.length; i++) - NavigationDrawerDestination( - label: Text(controller.titles[i]), - icon: controller.icons[i], + return BlocBuilder( + builder: (context, state) { + final controller = context.watch(); + return NavigationDrawer( + onDestinationSelected: (int index) { + controller.changePage(index); + }, + selectedIndex: controller.state.currentPage, + children: [ + const Align( + alignment: Alignment.centerRight, + child: CloseButton(), ), - ], - ), + for (var i = 0; i < controller.pages.length; i++) + NavigationDrawerDestination( + label: Text(controller.pages[i].title), + icon: const Icon(Icons.arrow_forward_ios_rounded), + selectedIcon: const Icon(Icons.arrow_forward_ios_rounded, + color: mainColor), + ), + ], + ); + }, ); } diff --git a/snow_portfolio/lib/presentation/screens/home/social_button.dart b/snow_portfolio/lib/presentation/screens/home/social_button.dart new file mode 100644 index 0000000..8e58993 --- /dev/null +++ b/snow_portfolio/lib/presentation/screens/home/social_button.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class SocialButton extends StatelessWidget { + const SocialButton({ + super.key, + required this.url, + required this.logo, + this.tooltip, + }); + + final Uri url; + final IconData logo; + final String? tooltip; + + @override + Widget build(BuildContext context) { + return IconButton( + tooltip: tooltip, + onPressed: () { + launchUrl(url); + }, + icon: FaIcon(logo), + ); + } +} diff --git a/snow_portfolio/lib/presentation/screens/projects/project_card.dart b/snow_portfolio/lib/presentation/screens/projects/project_card.dart deleted file mode 100644 index 60de398..0000000 --- a/snow_portfolio/lib/presentation/screens/projects/project_card.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import '../../../config/config.dart'; -import '../../../domain/models.dart'; -import 'project_image_view.dart'; - -class ProjectCard extends GetView { - final double rotationAngle; - final Project projectModel; - const ProjectCard( - {super.key, required this.rotationAngle, required this.projectModel}); - - @override - Widget build(BuildContext context) { - isPhone = context.width <= 800; - return Card( - elevation: 3, - shadowColor: Get.theme.colorScheme.primary.withOpacity(0.5), - child: SingleChildScrollView( - child: ResponsiveFlex( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - isPhone - ? infoSection() - : Expanded( - flex: 4, - child: infoSection(), - ), - ProjectImageView( - rotationAngle: rotationAngle, - imagePath: projectModel.image!, - ), - ], - ), - ), - ); - } - - Column infoSection() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - project(), - DevIconsList(iconList: projectModel.technologies!), - github(), - ], - ); - } - - Padding project() { - return Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Column( - children: [ - Text( - projectModel.title!, - style: const TextStyle( - fontSize: 35, - fontWeight: FontWeight.bold, - ), - ), - AutoSizeText( - projectModel.description!, - minFontSize: isPhone ? 15 : 20, - maxFontSize: 30, - maxLines: null, - ), - ], - ), - ); - } - - TextButton github() { - return TextButton.icon( - onPressed: () async { - await launchUrl(Uri.parse(projectModel.repository!)); - }, - icon: const FaIcon(FontAwesomeIcons.github), - label: Text( - projectModel.repository! - .substring(projectModel.repository!.lastIndexOf('/') + 1), - ), - ); - } -} diff --git a/snow_portfolio/lib/presentation/screens/projects/project_image_view.dart b/snow_portfolio/lib/presentation/screens/projects/project_image_view.dart deleted file mode 100644 index 07533fa..0000000 --- a/snow_portfolio/lib/presentation/screens/projects/project_image_view.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; - -class ProjectImageView extends StatelessWidget { - const ProjectImageView({ - super.key, - required this.rotationAngle, - required this.imagePath, - }); - - final double rotationAngle; - final String imagePath; - - @override - Widget build(BuildContext context) { - return Transform.rotate( - angle: rotationAngle, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), - border: Border.all( - color: Get.theme.colorScheme.primary, - width: 8, - ), - ), - child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 600, - maxHeight: 450, - minHeight: 200, - ), - child: Image.asset( - imagePath, - fit: BoxFit.contain, - ), - ), - ), - ); - } -} diff --git a/snow_portfolio/lib/presentation/screens/projects/project_page.dart b/snow_portfolio/lib/presentation/screens/projects/project_page.dart new file mode 100644 index 0000000..541e652 --- /dev/null +++ b/snow_portfolio/lib/presentation/screens/projects/project_page.dart @@ -0,0 +1,76 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import '../../../config/config.dart'; +import '../../../domain/models.dart'; + +class ProjectCard extends StatelessWidget { + final Project projectModel; + const ProjectCard({super.key, required this.projectModel}); + + @override + Widget build(BuildContext context) { + isPhone = context.width <= 800; + return Column( + children: [ + infoSection(), + Expanded( + child: Image.asset( + projectModel.image!, + fit: BoxFit.contain, + ), + ), + ], + ); + } + + Column infoSection() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + project(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + DevIconsList(iconList: projectModel.technologies!), + github(), + ], + ), + ], + ); + } + + Widget project() { + return Column( + children: [ + Text( + projectModel.title!, + style: const TextStyle( + fontSize: 35, + fontWeight: FontWeight.bold, + ), + ), + AutoSizeText( + projectModel.description!, + minFontSize: isPhone ? 15 : 20, + maxFontSize: 30, + maxLines: null, + ), + ], + ).paddingOnly(left: 8.0); + } + + TextButton github() { + return TextButton.icon( + onPressed: () async { + await launchUrl(Uri.parse(projectModel.repository!)); + }, + icon: const FaIcon(FontAwesomeIcons.github), + label: Text( + projectModel.repository! + .substring(projectModel.repository!.lastIndexOf('/') + 1), + ), + ); + } +} diff --git a/snow_portfolio/lib/presentation/screens/projects/projects_view.dart b/snow_portfolio/lib/presentation/screens/projects/projects_view.dart index 85ecac9..e538524 100644 --- a/snow_portfolio/lib/presentation/screens/projects/projects_view.dart +++ b/snow_portfolio/lib/presentation/screens/projects/projects_view.dart @@ -1,35 +1,90 @@ import 'package:flutter/material.dart'; -import 'package:card_swiper/card_swiper.dart'; -import 'package:get/get.dart'; -import '../../controllers/controllers.dart'; -import 'project_card.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:snow_portfolio/config/config.dart'; +import '../../bloc/bloc.dart'; +import 'project_page.dart'; -class ProjectsView extends GetView { +class ProjectsView extends StatelessWidget { const ProjectsView({super.key}); @override Widget build(BuildContext context) { - final isPhone = context.width <= 800; - return SizedBox( - height: Get.height, - child: Swiper( - itemBuilder: (BuildContext context, int index) => ProjectCard( - projectModel: controller.projectItems[index], - rotationAngle: isPhone ? 0 : (index % 2 == 0 ? 0.2 : -0.2), - ), - itemCount: controller.projectItems.length, - layout: SwiperLayout.TINDER, - itemWidth: double.infinity, - itemHeight: 600, - pagination: SwiperPagination( - builder: DotSwiperPaginationBuilder( - activeColor: Get.theme.colorScheme.primary, - color: Get.theme.colorScheme.secondary, + final controller = context.watch(); + return Column( + children: [ + Scrollbar( + controller: controller.scrollController, + child: SizedBox( + height: context.width * 0.1, + width: context.width, + child: ListView( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + controller: controller.scrollController, + children: List.generate( + controller.projectItems.length, + (index) { + return InkWell( + onTap: () { + controller.pageController.animateToPage( + index, + duration: const Duration(seconds: 1), + curve: Curves.easeInOutCubicEmphasized, + ); + controller.currentPage = index; + }, + onHover: (isHovering) { + controller.onHover(index, isHovering); + }, + child: Stack( + children: [ + AnimatedContainer( + duration: const Duration(seconds: 1), + curve: Curves.easeInOutCubicEmphasized, + width: context.width * + (controller.currentPage == index ? 0.2 : 0.1), + height: context.width * 0.1, + child: Image.asset( + controller.projectItems[index].image!, + fit: BoxFit.cover, + ), + ).paddingSymmetric(horizontal: 10), + Visibility( + visible: controller.currentPage == index + ? true + : controller.state.hoveringIndex == index, + child: Container( + width: context.width * + (controller.currentPage == index ? 0.2 : 0.1), + height: context.width * 0.1, + color: (controller.currentPage == index + ? mainColor + : Colors.black) + .withOpacity(0.5), + child: Text(controller.projectItems[index].title!) + .center(), + ).paddingSymmetric(horizontal: 10), + ), + ], + ), + ); + }, + ), + ), ), ), - control: SwiperControl( - color: Get.theme.colorScheme.primary, - ), - ), + SizedBox( + height: context.height, + child: PageView.builder( + controller: controller.pageController, + itemCount: controller.projectItems.length, + itemBuilder: (context, index) { + return ProjectCard( + projectModel: controller.projectItems[index], + ); + }, + ), + ).marginSymmetric(horizontal: 15), + ], ); } } diff --git a/snow_portfolio/lib/presentation/screens/screens.dart b/snow_portfolio/lib/presentation/screens/screens.dart index 97dcd63..a59a685 100644 --- a/snow_portfolio/lib/presentation/screens/screens.dart +++ b/snow_portfolio/lib/presentation/screens/screens.dart @@ -1,6 +1,4 @@ export 'about_me/about_me_view.dart'; -export 'extracurricular/extracurricular_view.dart'; export 'home/home_view.dart'; export 'projects/projects_view.dart'; -export 'skills/skills_view.dart'; -export 'volunteering/volunteering_view.dart'; \ No newline at end of file +export 'technologies/technologies_view.dart'; \ No newline at end of file diff --git a/snow_portfolio/lib/presentation/screens/skills/skills_view.dart b/snow_portfolio/lib/presentation/screens/skills/skills_view.dart deleted file mode 100644 index e14a9da..0000000 --- a/snow_portfolio/lib/presentation/screens/skills/skills_view.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:get/get.dart'; -import 'package:lottie/lottie.dart'; - -import '../../../config/config.dart'; -import '../../controllers/controllers.dart'; - -class SkillsView extends GetView { - const SkillsView({super.key}); - @override - Widget build(BuildContext context) { - isPhone = context.width <= 800; - return Stack( - children: [ - background(context.height), - ResponsiveFlex( - children: [ - education, - Expanded( - flex: 4, - child: SizedBox( - height: Get.height, - child: ListView( - children: [ - sectionOf( - controller.softSkillsHeader, - FontAwesomeIcons.lightbulb, - controller.softSkills, - ), - sectionOf( - controller.languagesHeader, - FontAwesomeIcons.language, - controller.languages, - ), - ], - ), - ), - ), - ], - ), - ], - ); - } - - ExpansionTile sectionOf(String title, IconData icon, List list) { - return ExpansionTile( - initiallyExpanded: !isPhone, - title: Text(title), - trailing: Icon(icon), - children: [ - for (final item in list) - ListTile( - title: Text(item), - ), - ], - ); - } - - Expanded get education { - return Expanded( - flex: 6, - child: SizedBox( - height: Get.height, - child: Column( - children: [ - ListTile( - title: Text( - controller.educationHeader, - ), - trailing: const Icon(FontAwesomeIcons.graduationCap), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: ActivityList(controller.education), - ), - ), - ], - ), - ), - ); - } - - SizedBox background(double height) { - return SizedBox( - height: height, - child: LottieBuilder.network( - 'https://lottie.host/5401a029-9aa7-48cd-b061-b8e12e5f21db/S9r2Z6rHnk.json', - fit: BoxFit.fitHeight, - ), - ); - } -} diff --git a/snow_portfolio/lib/presentation/screens/technologies/technologies_view.dart b/snow_portfolio/lib/presentation/screens/technologies/technologies_view.dart new file mode 100644 index 0000000..65f3589 --- /dev/null +++ b/snow_portfolio/lib/presentation/screens/technologies/technologies_view.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:snow_portfolio/config/config.dart'; + +import '../../bloc/bloc.dart'; + +class TechnologiesView extends StatefulWidget { + const TechnologiesView({Key? key}) : super(key: key); + + @override + _TechnologiesViewState createState() => _TechnologiesViewState(); +} + +class _TechnologiesViewState extends State + with TickerProviderStateMixin { + late final AnimationController _controllerLanguages; + late final AnimationController _controllerFrameworks; + late final AnimationController _controllerDatabases; + late final AnimationController _controllerTools; + final style = const TextStyle(fontSize: 20); + + @override + void initState() { + super.initState(); + _controllerLanguages = AnimationController( + duration: const Duration(seconds: 1), + vsync: this, + ); + _controllerFrameworks = AnimationController( + duration: const Duration(seconds: 1), + vsync: this, + ); + _controllerDatabases = AnimationController( + duration: const Duration(seconds: 1), + vsync: this, + ); + _controllerTools = AnimationController( + duration: const Duration(seconds: 1), + vsync: this, + ); + + _startAnimations(); + } + + void _startAnimations() async { + await Future.delayed(const Duration(seconds: 1)); + _controllerLanguages.forward(); + await Future.delayed(const Duration(seconds: 1)); + _controllerFrameworks.forward(); + await Future.delayed(const Duration(seconds: 1)); + _controllerDatabases.forward(); + await Future.delayed(const Duration(seconds: 1)); + _controllerTools.forward(); + } + + @override + Widget build(BuildContext context) { + final controller = context.watch(); + return Column( + key: ValueKey(context.watch().state.currentLocale.toString()), + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + FadeTransition( + opacity: _controllerLanguages, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(controller.languagesText, style: style), + DevIconsList(iconList: controller.languages, radius: 40), + ], + ), + ), + FadeTransition( + opacity: _controllerFrameworks, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(controller.frameworksText, style: style), + DevIconsList(iconList: controller.frameworks, radius: 40), + ], + ), + ), + FadeTransition( + opacity: _controllerDatabases, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(controller.databasesText, style: style), + DevIconsList(iconList: controller.databases, radius: 40), + ], + ), + ), + FadeTransition( + opacity: _controllerTools, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(controller.toolsText, style: style), + DevIconsList(iconList: controller.tools, radius: 40), + ], + ), + ), + ], + ); + } + + @override + void dispose() { + _controllerLanguages.dispose(); + _controllerFrameworks.dispose(); + _controllerDatabases.dispose(); + _controllerTools.dispose(); + super.dispose(); + } +} diff --git a/snow_portfolio/lib/presentation/screens/volunteering/volunteering_view.dart b/snow_portfolio/lib/presentation/screens/volunteering/volunteering_view.dart deleted file mode 100644 index 6cf1888..0000000 --- a/snow_portfolio/lib/presentation/screens/volunteering/volunteering_view.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:lottie/lottie.dart'; -import 'package:snow_portfolio/presentation/controllers/controllers.dart'; - -import '../../../config/config.dart'; - -class VolunteeringView extends GetView { - const VolunteeringView({super.key}); - @override - Widget build(BuildContext context) { - return ResponsiveFlex( - children: [ - Expanded( - flex: 6, - child: ActivityList(controller.volunteeringList), - ), - Expanded( - flex: 4, - child: LottieBuilder.network( - 'https://lottie.host/6821aded-7d39-493d-84b9-d9e2d6af0342/7AtgnPOrZn.json', - alignment: Alignment.centerRight, - ), - ), - ], - ); - } -} diff --git a/snow_portfolio/pubspec.lock b/snow_portfolio/pubspec.lock index 0ce8e84..b950c50 100644 --- a/snow_portfolio/pubspec.lock +++ b/snow_portfolio/pubspec.lock @@ -65,6 +65,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + bloc: + dependency: "direct main" + description: + name: bloc + sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49" + url: "https://pub.dev" + source: hosted + version: "8.1.2" boolean_selector: dependency: transitive description: @@ -249,6 +257,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + feedback: + dependency: "direct main" + description: + name: feedback + sha256: "3cb138a56a3f3914dd38471479c351ce6df377abb29c5ebe4042be5481fee271" + url: "https://pub.dev" + source: hosted + version: "3.0.0" ffi: dependency: transitive description: @@ -278,6 +294,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae + url: "https://pub.dev" + source: hosted + version: "8.1.3" flutter_launcher_icons: dependency: "direct dev" description: @@ -349,14 +373,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" - get: + get_it: dependency: "direct main" description: - name: get - sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e + name: get_it + sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7 url: "https://pub.dev" source: hosted - version: "4.6.6" + version: "7.6.7" glob: dependency: transitive description: @@ -365,6 +389,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: "07ee2436909f749d606f53521dc1725dd738dc5196e5ff815bc254253c594075" + url: "https://pub.dev" + source: hosted + version: "13.1.0" google_fonts: dependency: "direct main" description: @@ -517,6 +549,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" package_config: dependency: transitive description: @@ -621,6 +661,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + provider: + dependency: transitive + description: + name: provider + sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" + url: "https://pub.dev" + source: hosted + version: "6.1.1" pub_semver: dependency: transitive description: diff --git a/snow_portfolio/pubspec.yaml b/snow_portfolio/pubspec.yaml index 02313ff..dc845ea 100644 --- a/snow_portfolio/pubspec.yaml +++ b/snow_portfolio/pubspec.yaml @@ -1,14 +1,13 @@ name: snow_portfolio -version: 0.1.0 +version: 0.2.0 publish_to: none -description: "Alexander Nieves' resume." -environment: - sdk: '>=3.2.3 <4.0.0' +description: "Alexander Nieves' portfolio." +environment: + sdk: ">=3.2.3 <4.0.0" -dependencies: +dependencies: gap: ^3.0.1 - get: 4.6.6 - flutter: + flutter: sdk: flutter lottie: ^3.0.0 flutter_spinkit: ^5.2.0 @@ -25,18 +24,24 @@ dependencies: slang: ^3.28.0 slang_flutter: ^3.28.0 scrollable_positioned_list: ^0.3.8 + feedback: ^3.0.0 + go_router: ^13.1.0 + flutter_bloc: ^8.1.3 + bloc: ^8.1.2 + get_it: ^7.6.7 -dev_dependencies: +dev_dependencies: flutter_lints: ^3.0.1 flutter_native_splash: ^2.0.2 flutter_launcher_icons: ^0.13.1 - flutter_test: + flutter_test: sdk: flutter build_runner: ^2.4.7 slang_build_runner: ^3.28.0 -flutter: - assets: +flutter: + assets: + - assets/images/ - assets/icons/ - assets/images/projects/ uses-material-design: true @@ -51,8 +56,8 @@ flutter_launcher_icons: # dart run flutter_native_splash:create flutter_native_splash: web: true - + color: "#ffffff" image: assets/icons/splash-icon.png # Dark mode - color_dark: "#131516" \ No newline at end of file + color_dark: "#131516" diff --git a/snow_portfolio/web/index.html b/snow_portfolio/web/index.html index b732901..cff6d65 100644 --- a/snow_portfolio/web/index.html +++ b/snow_portfolio/web/index.html @@ -2,19 +2,6 @@ - @@ -24,13 +11,13 @@ - + - Alexander Portfolio + Alexander Nieves Portfolio