Skip to content

Commit

Permalink
Merge pull request #34 from PLGuerraDesigns/dev
Browse files Browse the repository at this point in the history
Bug Fixes & General Improvements
  • Loading branch information
PLGuerraDesigns authored Aug 10, 2024
2 parents 8c3add1 + cd1dde8 commit 395e984
Show file tree
Hide file tree
Showing 24 changed files with 196 additions and 102 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
## 2.5.5

- FIX: Fixed issue with router routing to the wrong page when the theme is toggled when navigating back from a different page. (Temporary fix for when the route is popped.)
- FIX: Fixed spacing issue in the home header banner.
- REVISED: Updated the home header banner subtitle to cycle through a list rather than just two.

## 2.5.4

- FIX: Fixed issue with the local video player restarting when the media browser is opened or closed.

## 2.5.3

- FIX: Fixed issue with current route not being updated when navigating to a new route. (Added a temporary fix for when the route is popped.)

## 2.5.2

- FIX: Fixed social media icons not displaying due to case sensitivity in the file path.
Expand Down
72 changes: 46 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
This web app is a portfolio of my work, projects, and research. <br />
You can find relevant publications, documents, source code, images, videos, and more here.

It is a static web app built using the [Flutter framework](https://flutter.dev/) and hosted on [GitHub Pages](https://pages.github.com/). <br />
It is a static web app built using the [Flutter framework](https://flutter.dev/), written in [Dart](https://dart.dev/), and hosted on [GitHub Pages](https://pages.github.com/). <br />

You can access the web app here: [https://plguerradesigns.github.io/portfolio](https://plguerradesigns.github.io/portfolio)

Expand Down Expand Up @@ -39,8 +39,8 @@ Try Flutter directly in your browser using [DartPad](https://dartpad.dev/?id=5c0
- my social media accounts
- relevant institutions/organizations/companies
- the source code of the web app
- the project issue tracker
- the project change log
- the app's issue tracker
- the app's change log
- A contact button that opens an email client with my email address

## Showcase
Expand All @@ -58,26 +58,26 @@ Try Flutter directly in your browser using [DartPad](https://dartpad.dev/?id=5c0
</tr>
<tr>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/dark/home.webp" alt="Home (Dark Mode)" width="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/dark/home.webp" alt="Home" width="300">
</td>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/dark/home_drawer.webp" alt="Home Drawer (Dark Mode)" height="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/dark/home.webp" alt="Home" height="300">
</td>
</tr>
<tr>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/dark/professional_experience.webp" alt="Professional Experience (Dark Mode)" width="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/dark/professional_experience.webp" alt="Professional Experience" width="300">
</td>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/dark/professional_experience.webp" alt="Professional Experience (Dark Mode)" height="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/dark/professional_experience.webp" alt="Professional Experience" height="300">
</td>
</tr>
<tr>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/dark/details.webp" alt="Details (Dark Mode)" width="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/dark/details.webp" alt="Details" width="300">
</td>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/dark/details.webp" alt="Details (Dark Mode)" height="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/dark/details.webp" alt="Details" height="300">
</td>

</table>
Expand All @@ -94,26 +94,26 @@ Try Flutter directly in your browser using [DartPad](https://dartpad.dev/?id=5c0
</tr>
<tr>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/light/home.webp" alt="Home (Light Mode)" width="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/light/home.webp" alt="Home" width="300">
</td>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/light/home.webp" alt="Home (Light Mode)" height="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/light/home.webp" alt="Home" height="300">
</td>
</tr>
<tr>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/light/projects.webp" alt="Projects (Light Mode)" width="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/light/projects.webp" alt="Projects" width="300">
</td>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/light/projects.webp" alt="Projects (Light Mode)" height="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/light/projects.webp" alt="Projects" height="300">
</td>
</tr>
<tr>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/light/details.webp" alt="Details (Light Mode)" width="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/desktop/light/details.webp" alt="Details" width="300">
</td>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/light/details.webp" alt="Details (Light Mode)" height="300">
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v2.5.0/mobile/light/details.webp" alt="Details" height="300">
</td>
</tr>
</table>
Expand Down Expand Up @@ -171,14 +171,6 @@ Try Flutter directly in your browser using [DartPad](https://dartpad.dev/?id=5c0
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v1.0.8/mobile/projects.webp" alt="Projects" height="300">
</td>
</tr>
<tr>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v1.0.8/desktop/project_details.webp" alt="Projects Details" width="300">
</td>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v1.0.8/mobile/home_drawer.webp" alt="Home Drawer" height="300">
</td>
<tr>
<td>
<img src="https://raw.githubusercontent.com/PLGuerraDesigns/portfolio/master/showcase/v1.0.8/desktop/contact.webp" alt="Contact" width="300">
</td>
Expand All @@ -198,6 +190,32 @@ Try Flutter directly in your browser using [DartPad](https://dartpad.dev/?id=5c0

</details>

## Design Notes

The web app is designed using the [Material Design](https://material.io/design) guidelines. <br />

[![Material Design UI Example](https://lh3.googleusercontent.com/kqa_LNBbbacJHfLL5ADPfJIcqHAeVIz3KMqy2PFGFHqQz5ir51Ww0APxKJt5J7EfRehqidtv4kxSlvmx5Je3A5jmH_y_jXbHWGIwsGyTINBP=s0)](https://m3.material.io/)

Try out the Material 3 Demo here: [https://flutter.github.io/samples/web/material_3_demo/](https://flutter.github.io/samples/web/material_3_demo/)

### Color Scheme

The color scheme was chosen by using the online tool [Coolors](https://coolors.co/) to generate a palette of my preference.

[![Coolors](https://res.cloudinary.com/coolors/image/upload/v1575544084/zendesk/generator_screen.png)](https://coolors.co/)

The color codes were then entered into the [Material Theme Builder Plugin](https://www.figma.com/community/plugin/1034969338659738588/material-theme-builder), for Figma, to generate a Material Theme that was exported to Dart code.

[![Material Theme Builder](https://s3-alpha-sig.figma.com/plugins/1034969338659738588/88380/6192b9f77bb59605a942d2a2efdebb6d974a0e02-cover?Expires=1724025600&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=hZ4LNZRwvYZ0Ng-y8arJ3lSTRISquMJHaJ0nvt5NDYXQchQyGALBBS2Gu-3Qk3JzA0iMzj5jybdb9bug1UdqUnBBaThT1pCbBy-5L0gjumzOCdC~RCbUiFAyc1qxUogIK-7~tbPREu22rBp2U1HqbGVPrajMIFx1Oqa2tPCIDrU8lsSV7S9V8km~zub9WiZK-xy-8hq3h0UFWFtiSPox8NR6RmIDrVhY4C-YgeriXGruvip-6NEffbXu-ehb4uqoAz0j0d7UbCSrjJ568ARrW8RUma-EeILu3m-YqWBSOAL9HV0vGZXriQ2EtNJON9ODmb608wUUCImnJWVJ6grQkA__)](https://www.figma.com/community/plugin/1034969338659738588/material-theme-builder)

### Fonts and Icons

The font used is [Roboto](https://fonts.google.com/specimen/Roboto) and the icons are from [Material Icons](https://fonts.google.com/icons).

[![Material Design Typography](https://lh3.googleusercontent.com/q88EBZbgu7lTffRRfgJmCXT9WCK_HzM23PlqBYQXMHolDawHK6WuD7gEGTzpoX1zDUoxr8lTrBdYAzZeB2mbwh6KkMlQTNZh7wIR6kKYMsE=s0)](https://fonts.google.com/specimen/Roboto)

[![Material Design Icons](https://firebasestorage.googleapis.com/v0/b/design-spec/o/projects%2Fm3%2Fimages%2Fl1dsjbqv-hero_7_weights.gif?alt=media&token=5ab64691-8cbb-4420-a176-a258ccd63d76)](https://fonts.google.com/icons)

## Development Notes

[![Build and Release](https://github.com/plguerradesigns/portfolio/actions/workflows/main.yml/badge.svg)](https://github.com/PLGuerraDesigns/portfolio/actions/workflows/main.yml)
Expand All @@ -212,13 +230,15 @@ There are three main branches in this repository:

- `master`: The master branch is the default branch and is protected. It contains the latest stable version of the web app.
- `dev`: The development branch is where new features are added and tested. It is merged into the master branch after testing.
- `published`: The published branch contains the latest build of the web app. This branch is used to host the web app on GitHub Pages.
- `published`: The published branch contains the build artifacts of the web app and is deployed to GitHub Pages.

[![git-kraken.png](https://i.postimg.cc/fTrTzny9/git-kraken.png)](https://www.gitkraken.com/)

The CI/CD pipeline is implemented using [GitHub Actions](https://github.com/features/actions). The pipeline consists of the following stages:

- Build: The Flutter web app is built using the `flutter build web` command.
- Release: The build artifacts are pushed to the `published` branch.
- Deploy: The `published` branch is deployed to GitHub Pages.
- Release: The build artifacts are merged into the `published` branch.
- Deploy: The latest build artifacts are deployed to GitHub Pages.

The pipeline is triggered automatically on every commit to the master branch.

Expand Down
4 changes: 2 additions & 2 deletions assets/json/projects.json
Original file line number Diff line number Diff line change
Expand Up @@ -628,9 +628,9 @@
"source": "thumbnail.webp"
},
{
"type": "localVideo",
"type": "youTubeVideo",
"caption": "F1 Sim Engineer Demo",
"source": "video_1.mp4"
"source": "4ROWmlwLq6M"
}
],
"externalLinks": [
Expand Down
2 changes: 2 additions & 0 deletions lib/common/routing/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ class AppRouter {
final String location = state.uri.toString();
final String goto = location.split('/').last;

appState.currentRoute = location;

final bool isAtProfessionalDetails =
location.contains(Routes.professional) &&
location.contains(Routes.details);
Expand Down
9 changes: 6 additions & 3 deletions lib/common/strings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ class Strings {
static const String currentLocation = 'VA, USA';
static const String lastUpdated = 'Updated AUG 2024';

static const List<String> headerSubtitles = <String>[
'Software Engineer • Innovator • Technologist',
'Give me a lever long enough and a fulcrum on which to place it, and I shall move the world. ~Archimedes',
'Men for Others'
];

static const String appName = 'PLG Portfolio';
static const String name = 'Pablo L. Guerra';
static const String subtitle =
'Software Engineer • Innovator • Technologist';
static const String motto = 'Men for Others';
static const String explore = 'Explore';
static const String expand = 'Expand';
static const String collapse = 'Collapse';
Expand Down
5 changes: 5 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'common/routing/app_router.dart';
import 'common/routing/routes.dart';
import 'common/strings.dart';
import 'common/theming/theme_notifier.dart';
import 'models/app_state.dart';
Expand Down Expand Up @@ -31,6 +32,10 @@ class _PortfolioAppState extends State<PortfolioApp> {

// Listen to theme changes and rebuild the application.
themeNotifier.addListener(() {
// ! This should be handled in AppRouter but redirect isn't being called
// ! on pop, so we're handling it here until it's fixed in GoRouter.
_appState.currentRoute = Routes.home;

setState(() {});
});
}
Expand Down
7 changes: 7 additions & 0 deletions lib/pages/details/details.controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,11 @@ class DetailsController extends ChangeNotifier {

context.go(route);
}

@override
void dispose() {
screenScrollController.dispose();
mediaController.dispose();
super.dispose();
}
}
6 changes: 6 additions & 0 deletions lib/pages/details/details.screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,12 @@ class DetailsScreenState extends State<DetailsScreen> {
);
}

@override
void dispose() {
_controller.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return MultiProvider(
Expand Down
35 changes: 19 additions & 16 deletions lib/pages/details/widgets/media_player/local_video_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,28 @@ class LocalVideoPlayer extends StatelessWidget {
});

/// The controller for the video player.
final VideoPlayerController videoPlayerController;
final VideoPlayerController? videoPlayerController;

@override
Widget build(BuildContext context) {
return FutureBuilder<void>(
future: videoPlayerController.initialize(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Chewie(
controller: ChewieController(
autoPlay: true,
aspectRatio: 16 / 9,
autoInitialize: true,
videoPlayerController: videoPlayerController,
),
);
}
return const Spinner();
},
if (videoPlayerController == null) {
return const Spinner();
}
return Chewie(
controller: ChewieController(
videoPlayerController: videoPlayerController!,
autoPlay: true,
aspectRatio: 16 / 9,
autoInitialize: true,
zoomAndPan: true,
showControlsOnInitialize: false,
hideControlsTimer: const Duration(milliseconds: 1500),
materialProgressColors: ChewieProgressColors(
backgroundColor: Colors.white10,
bufferedColor: Colors.white24,
playedColor: Colors.white38,
),
),
);
}
}
8 changes: 5 additions & 3 deletions lib/pages/details/widgets/media_player/media_viewer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class MediaViewer extends StatelessWidget {
required this.mediaItems,
required this.totalMediaCount,
required this.imagePageController,
required this.videoPlayerController,
});

/// The axis of the media player and browser.
Expand All @@ -31,16 +32,17 @@ class MediaViewer extends StatelessWidget {
/// The controller for the image gallery.
final PageController imagePageController;

/// The controller for the video player.
final VideoPlayerController? videoPlayerController;

/// Returns the media widget based on the media type.
Widget _media(MediaItem mediaItem) {
final MediaType mediaType = mediaItem.type;
switch (mediaType) {
case MediaType.youTubeVideo:
return CustomYouTubePlayer(videoId: mediaItem.source);
case MediaType.localVideo:
return LocalVideoPlayer(
videoPlayerController: VideoPlayerController.asset(mediaItem.source),
);
return LocalVideoPlayer(videoPlayerController: videoPlayerController);
case MediaType.localImage:
return ImageViewer(
imageProvider: AssetImage(mediaItem.source),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,30 @@ class MultiMediaPlayerController extends ChangeNotifier {
late PageController imagePageController;

/// The controller for the video player.
VideoPlayerController? videoPlayerController;
VideoPlayerController? _videoPlayerController;

/// The function to call to toggle the media browser.
late Function() _updateMediaBrowserVisibilityState;

/// The video player controller.
VideoPlayerController? get videoPlayerController {
if (_videoPlayerController?.dataSource != currentMediaItem.source) {
_disposeVideoPlayerController();
}

if (currentMediaItem.type == MediaType.localVideo &&
_videoPlayerController != null) {
return _videoPlayerController;
} else if (currentMediaItem.type == MediaType.localVideo &&
_videoPlayerController == null) {
_videoPlayerController = VideoPlayerController.asset(
currentMediaItem.source,
);
return _videoPlayerController;
}
return _videoPlayerController;
}

/// Toggle the media browser.
void toggleMediaBrowser() {
_updateMediaBrowserVisibilityState();
Expand All @@ -59,7 +78,8 @@ class MultiMediaPlayerController extends ChangeNotifier {
previousIndex = totalMediaCount - 1;
imagePageController.jumpToPage(previousIndex);
} else {
if (mediaItems[currentIndex].type == MediaType.youTubeVideo) {
if (<MediaType>[MediaType.youTubeVideo, MediaType.localVideo]
.contains(mediaItems[currentIndex].type)) {
imagePageController.jumpToPage(previousIndex);
} else {
await imagePageController.animateToPage(
Expand All @@ -80,7 +100,8 @@ class MultiMediaPlayerController extends ChangeNotifier {
nextIndex = 0;
imagePageController.jumpToPage(nextIndex);
} else {
if (mediaItems[currentIndex].type == MediaType.youTubeVideo) {
if (<MediaType>[MediaType.youTubeVideo, MediaType.localVideo]
.contains(mediaItems[currentIndex].type)) {
imagePageController.jumpToPage(nextIndex);
} else {
await imagePageController.animateToPage(
Expand All @@ -101,12 +122,16 @@ class MultiMediaPlayerController extends ChangeNotifier {
notifyListeners();
}

/// Dispose of the video player controller.
void _disposeVideoPlayerController() {
_videoPlayerController?.dispose();
_videoPlayerController = null;
}

@override
void dispose() {
imagePageController.dispose();
if (videoPlayerController != null) {
videoPlayerController!.dispose();
}
_disposeVideoPlayerController();
super.dispose();
}
}
Loading

0 comments on commit 395e984

Please sign in to comment.