getBreakpointSegments function
List<ResponsiveBreakpointSegment>
getBreakpointSegments(
- List<
ResponsiveBreakpoint> breakpoints, - ResponsiveBreakpoint defaultBreakpoint
Calculate breakpoint segments algorithm.
Complex logic to compute the breakpoint segments efficiently.
Implementation
List<ResponsiveBreakpointSegment> getBreakpointSegments(
List<ResponsiveBreakpoint> breakpoints,
ResponsiveBreakpoint defaultBreakpoint) {
// Mutable breakpoints holder.
List<ResponsiveBreakpoint> breakpointsHolder = [];
breakpointsHolder.addAll(breakpoints);
// Breakpoint segments holder.
List<ResponsiveBreakpointSegment> breakpointSegments = [];
// No breakpoints. Create segment from default breakpoint behavior.
if (breakpointsHolder.isEmpty) {
breakpointSegments.add(ResponsiveBreakpointSegment(
breakpoint: 0,
segmentType: defaultBreakpoint.behavior,
responsiveBreakpoint: defaultBreakpoint));
return breakpointSegments;
}
List<ResponsiveBreakpoint> breakpointTags =
breakpointsHolder.where((element) => element.isTag).toList();
breakpointsHolder =
breakpointsHolder.where((element) => !element.isTag).toList();
// Min Width is passed through the default breakpoint.
double minWidth = defaultBreakpoint.breakpoint;
// Breakpoint overrides MinWidth default.
ResponsiveBreakpoint? minWidthOverride = breakpointsHolder
.firstWhereOrNull((element) => element.breakpoint == minWidth);
if (minWidthOverride != null) {
breakpointsHolder.insert(
0,
ResponsiveBreakpoint(
breakpoint: minWidth,
name: defaultBreakpoint.name,
behavior: defaultBreakpoint.behavior,
scaleFactor: defaultBreakpoint.scaleFactor)
.merge(minWidthOverride));
} else {
// Add minWidth breakpoint. MinWidth generates
// a breakpoint segment and needs to be added.
breakpointsHolder.insert(
0,
ResponsiveBreakpoint(
breakpoint: minWidth,
name: defaultBreakpoint.name,
behavior: defaultBreakpoint.behavior,
scaleFactor: defaultBreakpoint.scaleFactor));
}
// Order breakpoints from smallest to largest.
// Perform ordering operation to allow breakpoints
// to be accepted in any order.
breakpointsHolder.sort(ResponsiveUtils.breakpointComparator);
breakpointTags.sort(ResponsiveUtils.breakpointComparator);
// Find the first breakpoint behavior.
ResponsiveBreakpoint initialBreakpoint = breakpointsHolder.first;
// Breakpoint variable that holds the active behavior.
// Used to calculate and remember the breakpoint behavior.
ResponsiveBreakpoint breakpointHolder = ResponsiveBreakpoint(
breakpoint: initialBreakpoint.breakpoint,
name: defaultBreakpoint.name,
behavior: defaultBreakpoint.behavior,
scaleFactor: defaultBreakpoint.scaleFactor);
// Construct initial segment that starts from 0.
// Initial segment inherits default behavior.
breakpointSegments.insert(
0,
ResponsiveBreakpointSegment(
breakpoint: 0,
segmentType: defaultBreakpoint.behavior,
// Convert initial AutoScaleDown behavior to AutoScale.
responsiveBreakpoint: breakpointHolder.copyWith(
behavior: (initialBreakpoint.isAutoScaleDown)
? ResponsiveBreakpointBehavior.AUTOSCALE
: defaultBreakpoint.behavior)));
// A counter to keep track of the actual number of added breakpoints.
// Needed because breakpoints are merged so not every
// for-loop iteration adds a breakpoint segment.
int breakpointCounter = 0;
// Calculate segments from breakpoints.
for (int i = 0; i < breakpointsHolder.length; i++) {
// Convenience variable.
ResponsiveBreakpoint breakpoint = breakpointsHolder[i];
// Segment calculation holder.
ResponsiveBreakpointSegment? breakpointSegmentHolder;
switch (breakpoint.behavior) {
case ResponsiveBreakpointBehavior.RESIZE:
case ResponsiveBreakpointBehavior.AUTOSCALE:
breakpointSegmentHolder = ResponsiveBreakpointSegment(
breakpoint: breakpoint.breakpoint,
segmentType: breakpoint.behavior,
responsiveBreakpoint: breakpoint);
break;
case ResponsiveBreakpointBehavior.AUTOSCALEDOWN:
// Construct override breakpoint segment.
// AutoScaleDown needs to override the breakpoint
// interval because responsive calculations are
// performed from 0 - ∞.
int overrideBreakpointIndex = breakpointCounter;
ResponsiveBreakpointSegment overrideBreakpointSegment =
breakpointSegments[overrideBreakpointIndex];
overrideBreakpointSegment = overrideBreakpointSegment.copyWith(
responsiveBreakpoint: overrideBreakpointSegment.responsiveBreakpoint
.copyWith(
breakpoint: breakpoint.breakpoint,
behavior: ResponsiveBreakpointBehavior.AUTOSCALE));
breakpointSegments[overrideBreakpointIndex] = overrideBreakpointSegment;
// AutoScaleDown acts as an AutoScale breakpoint
// in the 0 - ∞ direction.
breakpointSegmentHolder = ResponsiveBreakpointSegment(
breakpoint: breakpoint.breakpoint,
segmentType: breakpoint.behavior,
responsiveBreakpoint: ResponsiveBreakpoint(
breakpoint: breakpoint.breakpoint,
name: breakpoint.name,
behavior: ResponsiveBreakpointBehavior.AUTOSCALE,
scaleFactor: breakpoint.scaleFactor));
break;
case ResponsiveBreakpointBehavior.TAG:
break;
}
// Update holder with active breakpoint
breakpointHolder = breakpoint;
// Merge duplicate segments.
// Compare current segment to previous segment.
if (breakpointSegments.last.breakpoint ==
breakpointSegmentHolder!.breakpoint) {
breakpointSegments[breakpointSegments.length - 1] =
breakpointSegments.last.merge(breakpointSegmentHolder);
continue;
}
breakpointSegments.add(breakpointSegmentHolder);
breakpointCounter += 1;
}
// Add tags to segments.
for (int i = 0; i < breakpointTags.length; i++) {
// Convenience variable.
ResponsiveBreakpoint breakpointTag = breakpointTags[i];
ResponsiveBreakpointSegment breakpointSegmentHolder =
breakpointSegments.reversed.firstWhere(
(element) => element.breakpoint <= breakpointTag.breakpoint);
int breakpointHolderIndex =
breakpointSegments.indexOf(breakpointSegmentHolder);
if (breakpointSegmentHolder.breakpoint == breakpointTag.breakpoint) {
breakpointSegments[breakpointHolderIndex] = ResponsiveBreakpointSegment(
breakpoint: breakpointSegmentHolder.breakpoint,
segmentType: breakpointSegmentHolder.segmentType,
responsiveBreakpoint:
breakpointSegmentHolder.responsiveBreakpoint.merge(breakpointTag),
);
} else {
breakpointSegments.insert(
breakpointHolderIndex + 1,
ResponsiveBreakpointSegment(
breakpoint: breakpointTag.breakpoint,
segmentType: breakpointTag.behavior,
responsiveBreakpoint: breakpointSegmentHolder.responsiveBreakpoint
.merge(breakpointTag)),
);
}
}
return breakpointSegments;
}