1667612758
Grafana Phlare is an open source software project for aggregating continuous profiling data. Continuous profiling is an observability signal that allows you to understand your workload's resources (CPU, memory, etc...) usage down to the exact lines of code.
Grafana Phlare is fully integrated with Grafana allowing you to correlate with other observability signals, like metrics, logs, and traces.
Core features of Grafana Phlare include:
For information about how to deploy Grafana Phlare, refer to Deploy Grafana Phlare.
If you’re new to Grafana Phlare, read the Getting started guide.
Before deploying Grafana Phlare in a production environment, read:
Refer to the following links to access Grafana Phlare documentation:
To contribute to Grafana Phlare, refer to Contributing to Grafana Phlare.
If you have any questions or feedback regarding Grafana Phlare, join the Grafana Phlare Discussion. Alternatively, consider joining the monthly Grafana Phlare Community Call.
Your feedback is always welcome, and you can also share it via the #phlare
Slack channel.
Author: grafana
Source Code: https://github.com/grafana/phlare
License: AGPL-3.0 license
1597157520
High availability is the description of a system designed to be fault-tolerant, highly dependable, operates continuously without intervention, or having a single point of failure. These systems are highly sought after to increase the availability and uptime required to keep an infrastructure running without issue. The following characteristics define a High Availability system.
High-availability server clusters (aka HA Clusters) is defined as a group of servers which support applications or services that can be utilized reliably with a minimal amount of downtime. These server clusters function using a type of specialized software that utilizes redundancy to achieve mission-critical levels of five9’s uptime. Currently, approximately 60% of businesses require five9’s or greater to provide vital services for their businesses.
High availability software capitalizes on the redundant software installed on multiple systems by grouping or clustering together a group of servers focusing on a common goal in case components fail. Without this form of clustering, if the application or website crashes, the service will not be available until the servers are repaired. HA clustering addresses these situations by detecting the faults and quickly restarting or replacing the server or service or server with a new process that does not require human intervention. This is defined as a “failover” model.
The illustration below demonstrates a simple two node high availability cluster.
High Availability clusters are often used for mission-critical databases, data sharing, applications, and e-commerce websites spread over a network. High Availability implementations build redundancy within a cluster to remove any one single point of failure, including across multiple network connections and data storage, which can be connected redundantly via geographically diverse storage area networks.
High Availability clustered servers usually use a replication methodology called Heartbeat that is used to monitor each node’s status and health within the cluster over a private network connection. One critical circumstance all clustering software must be able to address is called split-brain, which occurs when all private internal links go down simultaneously, but the nodes in the cluster continue to run. If this occurs, every node within the cluster may incorrectly determine that all the other nodes have gone down and attempt to start services that other nodes may still be running. This condition of duplicate instances running similar services, which could cause data corruption on the system.
A typical version of high availability software provides attributes that include both hardware and software redundancy. These features include:
Fault tolerance is defined as the ability for a system’s infrastructure to foresee and withstand errors and provide an automatic response to those issues if encountered. The primary quality of these systems is advanced design factors, which can be called upon should a problem occur. Being able to configure an infrastructure that envisions every possible solution is a considerable task that involves the knowledge and experience to counter the multiple concerns before they occur. System architects who design such frameworks will have the methodologies which envision the means to alleviate these problems in advance, and the ability to implement these frameworks.
The following redundancy methodologies are available and should be reviewed during the initial stages of design and implementation.
As models progress from Nx to 2Nx, the cost factor also increases exponentially as for truly redundant systems that require uptime. These modalities are critical for stability and availability.
One of the central tenants of a high availability system is uptime. Uptime is of premier importance, especially if the purpose of a system is to provide an essential service like the 911 systems that respond to emergent situations. In business, having a high availability system is required to ensure a vital service remains online. One example would be an ISP or other service that cannot tolerate a loss of function. These systems must be designed with high availability and fault tolerance to ensure reliability and availability while minimizing downtime.
Should an error occur, the system will adapt and compensate for the issue while remaining up and online. Building this type of system requires forethought and planning for the unexpected. Being able to foresee the problems in advance, and planning for their resolution is one of the main qualities of a high availability system.
Should the system encounter an issue like a traffic spike or an increase in resource usage, the system’s ability to scale to meet those needs should be automatic and immediate. Building features like these into the system will provide the system’s ability to respond quickly to any change in the systemic functionality of the architectures processes.
Five 9’s is the industry standard of measure of uptime. This measurement can be related to the system itself, the system processes within a framework, or the program operating inside an infrastructure. This estimation is often related to the program being delivered to clients in the form or a website or web application. A systems Availability can be measured as the percentage of time that systems are available by using this equation: x = (n – y) * 100/n. This formula denotes that where “n” is the total amount of minutes within a calendar month, and “y” is the amount of minutes that service is inaccessible within a calendar month. The table below outlines downtime related to the percentage of “9’s” represented.
**Availability %**90%
(“1 Nine“)99%
(“2 Nines“)99.9%
(“3 Nines“)99.99%
(“4 Nines“)99.999%
(“5 Nines“)Downtime/Year36.53 days3.65 days8.77 hours52.60 minutes5.26 minutes
As we can see, the higher the number of “9’s”, the more uptime is provided. A high availability system’s goal is to achieve a minimal amount of potential downtime to ensure the system is always available to provide the designated services.
One of the main High Availability components is called Heartbeat. Heartbeat is a daemon which works with a cluster management software like Pacemaker that is designed specifically for high-availability clustering resource management. Its most important characteristics are:
The first segment of a highly available system is the clearly designed utilization of clustered application servers that are engineered in advance to distribute load amongst the whole cluster, which includes the ability to failover to a secondary and possibly a tertiary system.
The second division includes the need for database scalability. This entails the requirement of scaling, either horizontally or vertically, using multiple master replication, and a load balancer to improve the stability and uptime of the database.
#tutorials #2nx models #architecture #autonomous #availability #backups #best practice #clustering #deployment #design #disaster recovery #downtime #engineered #fault tolerance #ha cluster #heartbeat #high availability #infrastructure #monitoring #node #nx models #orchestrated #pacemaker #redundancy #reliability #replication #scalability #single point of failure #split brain #system #testing #uptime
1667612758
Grafana Phlare is an open source software project for aggregating continuous profiling data. Continuous profiling is an observability signal that allows you to understand your workload's resources (CPU, memory, etc...) usage down to the exact lines of code.
Grafana Phlare is fully integrated with Grafana allowing you to correlate with other observability signals, like metrics, logs, and traces.
Core features of Grafana Phlare include:
For information about how to deploy Grafana Phlare, refer to Deploy Grafana Phlare.
If you’re new to Grafana Phlare, read the Getting started guide.
Before deploying Grafana Phlare in a production environment, read:
Refer to the following links to access Grafana Phlare documentation:
To contribute to Grafana Phlare, refer to Contributing to Grafana Phlare.
If you have any questions or feedback regarding Grafana Phlare, join the Grafana Phlare Discussion. Alternatively, consider joining the monthly Grafana Phlare Community Call.
Your feedback is always welcome, and you can also share it via the #phlare
Slack channel.
Author: grafana
Source Code: https://github.com/grafana/phlare
License: AGPL-3.0 license
1598419500
Building a Reactive System is all about the balance between consistency and availability and the consequences of picking one over the other. This article mainly focuses on consistency and availability and how they impact the scalability of a system.
A system is scalable if it can meet the increase in demand while remaining responsive.
It is consistent if all the nodes show the same data at the same time.
It is available if it remains responsive despite any failures.
Scalability and performance are related but different concepts and we need to understand what the difference is.
Scalability is the number of requests system can handle at a time, i.e. load. It’s about optimizing the ability to handle load, which means improving how many requests system can handle at a time. Performance on the other hand is the time system takes to complete a single request, i.e. latency. It’s about optimizing the response time, which means improving how quickly system can handle a single request.
Performance has a limit on reducing the response time, and we will eventually reach that limit. Whereas, scalability has no theoretical limit. We may be restricted by the implementation. But in a perfectly scalable system, we could scale forever.
So when we build Reactive Micro-services we tend to focus on improving scalability than improving performance.
Measurement like requests-per-second actually measures both. This makes it a valuable metric because we can use it to see whether we have improved our scalability or our performance. But it also means that it is somewhat restrictive in the sense that if it improves we can’t tell which one changed. So if we want to know where that improvement came from then we have to track scalability and performance individually.
Distributed systems are systems that are separated by space. This means, the system could be deployed across multiple data centers or within the same data center, or just deployed to different hardware or to the same hardware.
Even if it’s deployed to the same hardware, a distributed system is one where information has to be transferred between different parts of that system and when that information is transferred it’s crossing some sort of space. It could be going over a local network, or it could be writing to a disk, or it could be writing to a database.
Information cannot be transferred instantaneously, it takes some time. Granted that time could be very small but there is an amount of time that elapses during the transfer of information. Within that time duration when the transfer the information takes place, the state of original sender may change.
The key here is to recognize that when we are dealing with a distributed system, we are always dealing with stale data. Reality is basically eventually consistent.
When a system stops receiving updates at least for some period of time, we can guarantee that all parts of the system will eventually converge on the same state. Thus in this way we can reach that level of consistency.
Common source control tools (Git, Subversion, etc) operate on an eventually consistent model. They rely on a later merge operation in order to bring things back into alignment. That’s how modern source control tools achieve consistency and it’s all an eventually consistent system.
Traditional monolithic architectures are usually based around strong consistency they use a strongly consistent database like a SQL database.
What is Strong Consistency?
When all members of a system agree on the state, before it becomes available, then we reach the level of strong consistency.
We can achieve strong consistency by introducing mechanisms like locks. Distributed system problem occurs when we have multiple things which are responsible for the same piece of data. As long as only one thing is responsible for that data, as long as we only have one instance of the lock, it’s not a distributed system problem anymore. Thus in this way we can resolve the distributed system problem by using a non distributed resource(lock).
But when we introduce a lock, it introduces overhead in the form of contention. That overhead has consequences to our ability to be elastic, to be resilient, and it has other consequences as well.
#microservices #reactive architecture #tech blogs #cap theorm #laws of scalability #reactive microservices #reactive systems #scalability #scalable systems
1670643156
macos_ui
Flutter widgets and themes implementing the current macOS design language.
Check out our interactive widget gallery online at https://groovinchip.github.io/macos_ui/#/
Guides, codelabs, and other documentation can be found at https://macosui.dev
pub.dev shows that macos_ui
only supports macOS. This is because macos_ui
calls some native code, and therefore specifies macOS as a plugin platform in the pubspec.yaml
file. macos_ui
will work on any platform that Flutter supports, but you will get best results on macOS.
The features of macos_ui
that will not work on platforms other than macOS due to calling native code are:
MacosColors.controlAccentColor()
functionMacosColorWell
widgetContributing & Resources
Layout
Icons
Buttons
Dialogs & Sheets
Fields & Labels
Indicators
Selectors
macos_ui
welcomes contributions! Please see CONTRIBUTING.md
for more information.
Layout
MacosWindow
is the basic frame for a macOS-style layout.
It supports a Sidebar
on the left, an optional TitleBar
at the top, and the rest of the window is typically filled out with a MacosScaffold
.
A scope for the MacosWindow
is provided by MacosWindowScope
. The sidebar can be toggled with MacosWindowScope.of(context).toggleSidebar()
. Please note that you must wrap your MacosScaffold
in a Builder
widget in order for this to work properly.
The MacosScaffold
is what you might call a "page".
The scaffold has a toolbar
property and a children
property. children
accepts a ContentArea
widget and multiple ResizablePane
widgets. To catch navigation or routes below the scaffold, consider wrapping the MacosScaffold
in a CupertinoTabView
. By doing so, navigation inside the MacosScaffold
will be displayed inside the MacosScaffold
area instead of covering the entire window. To push a route outside a MacosScaffold
wrapped in a CupertinoTabView
, use the root navigator Navigator.of(context, rootNavigator: true)
See the documentation for customizations and ToolBar
examples.
A new look for macOS apps was introduced in Big Sur (macOS 11). To match that look in your Flutter app, like our screenshots, your macos/Runner/MainFlutterWindow.swift
file should look like this:
import Cocoa
import FlutterMacOS
class BlurryContainerViewController: NSViewController {
let flutterViewController = FlutterViewController()
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError()
}
override func loadView() {
let blurView = NSVisualEffectView()
blurView.autoresizingMask = [.width, .height]
blurView.blendingMode = .behindWindow
blurView.state = .active
if #available(macOS 10.14, *) {
blurView.material = .sidebar
}
self.view = blurView
}
override func viewDidLoad() {
super.viewDidLoad()
self.addChild(flutterViewController)
flutterViewController.view.frame = self.view.bounds
flutterViewController.view.autoresizingMask = [.width, .height]
self.view.addSubview(flutterViewController.view)
}
}
class MainFlutterWindow: NSWindow, NSWindowDelegate {
override func awakeFromNib() {
delegate = self
let blurryContainerViewController = BlurryContainerViewController()
let windowFrame = self.frame
self.contentViewController = blurryContainerViewController
self.setFrame(windowFrame, display: true)
if #available(macOS 10.13, *) {
let customToolbar = NSToolbar()
customToolbar.showsBaselineSeparator = false
self.toolbar = customToolbar
}
self.titleVisibility = .hidden
self.titlebarAppearsTransparent = true
if #available(macOS 11.0, *) {
// Use .expanded if the app will have a title bar, else use .unified
self.toolbarStyle = .unified
}
self.isMovableByWindowBackground = true
self.styleMask.insert(NSWindow.StyleMask.fullSizeContentView)
self.isOpaque = false
self.backgroundColor = .clear
RegisterGeneratedPlugins(registry: blurryContainerViewController.flutterViewController)
super.awakeFromNib()
}
func window(_ window: NSWindow, willUseFullScreenPresentationOptions proposedOptions: NSApplication.PresentationOptions = []) -> NSApplication.PresentationOptions {
return [.autoHideToolbar, .autoHideMenuBar, .fullScreen]
}
func windowWillEnterFullScreen(_ notification: Notification) {
self.toolbar?.isVisible = false
}
func windowDidExitFullScreen(_ notification: Notification) {
self.toolbar?.isVisible = true
}
}
See this issue comment for more details on the new look and explanations for how it works.
Please note that if you are using a title bar (TitleBar
) in your MacosWindow
, you should set the toolbarStyle
of NSWindow to .expanded
, in order to properly align the close, minimize, zoom window buttons. In any other case, you should keep it as .unified
. This must be set beforehand, i.e. it cannot be switched in runtime.
Creates a toolbar in the MacosScaffold
. The toolbar appears below the title bar (if present) of the macOS app or integrates with it, by using its title
property.
A toolbar provides convenient access to frequently used commands and features (toolbar items). Different routes of your app could have different toolbars.
Toolbar items include ToolBarIconButton
, ToolBarPulldownButton
, and ToolBarSpacer
widgets, and should be provided via the items
property. The action of every toolbar item should also be provided as a menu bar command of your app.
Toolbars look best and are easiest to understand when they contain elements of the same type (so either use labels for every toolbar item or not).
You can use the ToolBarSpacer
widgets to set the grouping of the different toolbar actions.
An example toolbar would be:
ToolBar(
title: const Text('Untitled Document'),
titleWidth: 200.0,
leading: MacosBackButton(
onPressed: () => debugPrint('click'),
fillColor: Colors.transparent,
),
actions: [
ToolBarIconButton(
label: "Add",
icon: const MacosIcon(
CupertinoIcons.add_circled,
),
onPressed: () => debugPrint("Add..."),
showLabel: true,
),
const ToolBarSpacer(),
ToolBarIconButton(
label: "Delete",
icon: const MacosIcon(
CupertinoIcons.trash,
),
onPressed: () => debugPrint("Delete"),
showLabel: false,
),
ToolBarPullDownButton(
label: "Actions",
icon: CupertinoIcons.ellipsis_circle,
items: [
MacosPulldownMenuItem(
label: "New Folder",
title: const Text("New Folder"),
onTap: () => debugPrint("Creating new folder..."),
),
MacosPulldownMenuItem(
label: "Open",
title: const Text("Open"),
onTap: () => debugPrint("Opening..."),
),
],
),
]
),
This builds this simple toolbar:
Other toolbar examples:
Toolbar with icon buttons (no labels):
Toolbar with icon buttons and labels:
Toolbar with a pulldown button open:
Toolbar with title bar above (also see the note above):
You can also create your own CustomToolbarItem
to include any type of widget in the toolbar:
// Add a grey vertical line as a custom toolbar item:
CustomToolbarItem(
inToolbarBuilder: (context) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(color: Colors.grey, width: 1, height: 30),
),
inOverflowedBuilder: (context) =>
Container(color: Colors.grey, width: 30, height: 1),
),
A widget that aims to approximate the [ListTile] widget found in Flutter's material library.
Usage:
MacosListTile(
leading: const Icon(CupertinoIcons.lightbulb),
title: Text(
'A robust library of Flutter components for macOS',
style: MacosTheme.of(context).typography.headline,
),
subtitle: Text(
'Create native looking macOS applications using Flutter',
style: MacosTheme.of(context).typography.subheadline.copyWith(
color: MacosColors.systemGrayColor,
),
),
),
A multipage interface that displays one page at a time. Must be used in a StatefulWidget
.
You can control the placement of the tabs using the position
property.
Usage:
final _controller = MacosTabController(
initialIndex: 0,
length: 3,
);
...
MacosTabView(
controller: _controller,
tabs: const [
MacosTab(
label: 'Tab 1',
),
MacosTab(
label: 'Tab 2',
),
MacosTab(
label: 'Tab 3',
),
],
children: const [
Center(
child: Text('Tab 1'),
),
Center(
child: Text('Tab 2'),
),
Center(
child: Text('Tab 3'),
),
],
),
Icons
A MacosIcon
is identical to a regular Icon
in every way with one exception - it respects a MacosTheme
. Use it the same way you would a regular icon:
MacosIcon(
CupertinoIcons.add,
// color: CupertinoColors.activeBlue.color,
// size: 20,
),
Buttons
A checkbox is a type of button that lets the user choose between two opposite states, actions, or values. A selected checkbox is considered on when it contains a checkmark and off when it's empty. A checkbox is almost always followed by a title unless it appears in a checklist. Learn more
Off | On | Mixed |
---|---|---|
Here's an example of how to create a basic checkbox:
bool selected = false;
MacosCheckbox(
value: selected,
onChanged: (value) {
setState(() => selected = value);
},
)
To make a checkbox in the mixed
state, set value
to null
.
A help button appears within a view and opens app-specific help documentation when clicked. All help buttons are circular, consistently sized buttons that contain a question mark icon. Learn more
Here's an example of how to create a help button:
HelpButton(
onPressed: () {
print('pressed help button'),
},
)
You can customize the help button appearance and behaviour using the HelpButtonTheme
, but it's not recommended by apple to change help button's appearance.
A radio button is a small, circular button followed by a title. Typically presented in groups of two to five, radio buttons provide the user a set of related but mutually exclusive choices. A radio button’s state is either on (a filled circle) or off (an empty circle). Learn more
Here's an example of how to create a basic radio button:
bool selected = false;
MacosRadioButton(
value: selected,
onChanged: (value) {
setState(() => selected = value);
},
),
A pull-down button (often referred to as a pull-down menu) is a type of pop-up button that, when clicked, displays a menu containing a list of choices. The menu appears below the button. Once the menu is displayed onscreen, it remains open until the user chooses a menu item, clicks outside of the menu, switches to another app, or quits the app; or until the system displays an alert. Learn more
Use a pull-down button to present a list of commands. A pull-down button can either show a title
or an icon
to describe the contents of the button's menu. If you use an icon, make sure it clearly communicates the button’s purpose.
If items
is null, the button will be disabled (greyed out).
A title
or an icon
must be provided, to be displayed as the pull-down button's title, but not both at the same time.
The menu can also be navigated with the up/down keys and an action selected with the Return key.
It can also appear in the toolbar, via the ToolBarPulldownButton
widget.
Dark Theme | Light Theme |
---|---|
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
Here's an example of how to create a basic pull-down button:
MacosPulldownButton(
title: "Actions",
// Or provide an icon to use as title:
// icon: CupertinoIcons.ellipsis_circle,
items: [
MacosPulldownMenuItem(
title: const Text('Save'),
onTap: () => debugPrint("Saving..."),
),
MacosPulldownMenuItem(
title: const Text('Save as...'),
onTap: () => debugPrint("Opening Save As dialog..."),
),
const MacosPulldownMenuDivider(),
MacosPulldownMenuItem(
enabled: false,
title: const Text('Export'),
onTap: () => debugPrint("Exporting"),
),
],
),
A pop-up button (often referred to as a pop-up menu) is a type of button that, when clicked, displays a menu containing a list of mutually exclusive choices. The menu appears on top of the button. Like other types of menus, a pop-up button’s menu can include separators and symbols like checkmarks. After the menu is revealed, it remains open until the user chooses a menu item, clicks outside of the menu, switches to another app, or quits the app; or until the system displays an alert. Learn more
The type T
of the MacosPopupButton
is the type of the value that each pop-up menu item represents. All the entries in a given menu must represent values with consistent types. Typically, an enum
is used. Each MacosPopupMenuItem
in items must be specialized with that same type argument.
The onChanged
callback should update a state variable that defines the pop-up menu's value. It should also call State.setState
to rebuild the pop-up button with the new value.
When there are menu items that cannot be displayed within the available menu constraints, a caret is shown at the top or bottom of the open menu to signal that there are items that are not currently visible.
The menu can also be navigated with the up/down keys and an item selected with the Return key.
Dark Theme | Light Theme |
---|---|
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
Here's an example of how to create a basic pop-up button:
String popupValue = 'One';
MacosPopupButton<String>(
value: popupValue,
onChanged: (String? newValue) {
setState(() {
popupValue = newValue!;
});
},
items: <String>['One', 'Two', 'Three', 'Four']
.map<MacosPopupMenuItem<String>>((String value) {
return MacosPopupMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
A push button appears within a view and initiates an instantaneous app-specific action, such as printing a document or deleting a file. Push buttons contain text—not icons—and often open a separate window, dialog, or app so the user can complete a task. Learn more
Dark Theme | Light Theme |
---|---|
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
Here's an example of how to create a basic push button:
PushButton(
child: Text('button'),
buttonSize: ButtonSize.large,
onPressed: () {
print('button pressed');
},
),
A switch is a visual toggle between two mutually exclusive states — on and off. A switch shows that it's on when the accent color is visible and off when the switch appears colorless. Learn more
On | Off |
---|---|
![]() | ![]() |
Here's an example of how to create a basic toggle switch:
bool selected = false;
MacosSwitch(
value: selected,
onChanged: (value) {
setState(() => selected = value);
},
),
Displays one or more navigational tabs in a single horizontal group. Used by MacosTabView
to navigate between the different tabs of the tab bar.
The typical usage of this widget is by MacosTabView
, to control the navigation of its children. You do not need to specify a MacosSegmentedControl
with your MacosTabView
, as it is built by that widget.
Dialogs and Sheets
Usage:
showMacosAlertDialog(
context: context,
builder: (_) => MacosAlertDialog(
appIcon: FlutterLogo(
size: 56,
),
title: Text(
'Alert Dialog with Primary Action',
style: MacosTheme.of(context).typography.headline,
),
message: Text(
'This is an alert dialog with a primary action and no secondary action',
textAlign: TextAlign.center,
style: MacosTheme.of(context).typography.headline,
),
primaryButton: PushButton(
buttonSize: ButtonSize.large,
child: Text('Primary'),
onPressed: () {},
),
),
);
Usage:
showMacosSheet(
context: context,
builder: (_) => const MacosuiSheet(),
);
Fields
A text field is a rectangular area in which the user enters or edits one or more lines of text. A text field can contain plain or styled text.
Here's an example of how to create a basic text field:
MacosTextField(
placeholder: 'Type some text here',
)
A search field is a style of text field optimized for performing text-based searches in a large collection of values.
When the user starts typing into the search field, a list of selectable results appears in an overlay below (or above) the field.
Dark Theme | Light Theme |
---|---|
![]() | ![]() |
Here's an example of how to create a search field:
MacosSearchField(
placeholder: 'Search for a country...',
results: countries.map((e) => SearchResultItem(e)).toList(),
onResultSelected: (resultItem) {
debugPrint(resultItem.searchKey);
},
)
Check the examples/fields_page
for more examples.
Labels
Labels are a short description of what an element on the screen does.
Tooltips succinctly describe how to use controls without shifting people’s focus away from the primary interface. Help tags appear when the user positions the pointer over a control for a few seconds. A tooltip remains visible for 10 seconds, or until the pointer moves away from the control.
Dark Theme | Light Theme |
---|---|
![]() | ![]() |
To create a tooltip, wrap any widget on a MacosTooltip
:
MacosTooltip(
message: 'This is a tooltip',
child: Text('Hover or long press to show a tooltip'),
),
You can customize the tooltip the way you want by customizing the theme's TooltipTheme
. A tooltip automatically adapts to its environment, responding to touch and pointer events. To use a tooltip with a toolbar item, provide it with a tooltipMessage
property.
Indicators
Don’t make people sit around staring at a static screen waiting for your app to load content or perform lengthy data processing operations. Use progress indicators to let people know your app hasn't stalled and to give them some idea of how long they’ll be waiting.
Progress indicators have two distinct styles:
People don't interact with progress indicators; however, they are often accompanied by a button for canceling the corresponding operation. Learn more
A ProgressCircle
can be either determinate or indeterminate.
Determinate Progress Circle | Indeterminate Progress Circle |
---|---|
![]() | ![]() |
Here's an example of how to create an indeterminate progress circle:
ProgressCircle(
value: null,
),
You can provide a non-null value to value
to make the progress circle determinate.
A ProgressBar
can only be determinate.
Here's an example of how to create a determinate progress bar:
ProgressBar(
value: 30,
)
A level indicator graphically represents of a specific value within a range of numeric values. It’s similar to a slider in purpose, but more visual and doesn’t contain a distinct control for selecting a value—clicking and dragging across the level indicator itself to select a value is supported, however. A level indicator can also include tick marks, making it easy for the user to pinpoint a specific value in the range. There are three different level indicator styles, each with a different appearance, for communicating capacity, rating, and relevance.
A capacity indicator illustrates the current level in relation to a finite capacity. Capacity indicators are often used when communicating factors like disk and battery usage. Learn more
Continuous | Discrete |
---|---|
![]() | ![]() |
A horizontal translucent track that fills with a colored bar to indicate the current value. Tick marks are often displayed to provide context. | A horizontal row of separate, equally sized, rectangular segments. The number of segments matches the total capacity, and the segments fill completely—never partially—with color to indicate the current value. |
Here's an example of how to create an interactive continuous capacity indicator:
double value = 30;
CapacityIndicator(
value: value,
discrete: false,
onChanged: (v) {
setState(() => value = v);
},
),
You can set discrete
to true
to make it a discrete capacity indicator.
A rating indicator uses a series of horizontally arranged graphical symbols to communicate a ranking level. The default symbol is a star.
A rating indicator doesn’t display partial symbols—its value is rounded in order to display complete symbols only. Within a rating indicator, symbols are always the same distance apart and don't expand or shrink to fit the control. Learn more
Here's an example of how to create an interactive rating indicator:
double value = 3;
RatingIndicator(
amount: 5,
value: value,
onChanged: (v) {
setState(() => value = v);
}
)
A relevance indicator communicates relevancy using a series of vertical bars. It often appears in a list of search results for reference when sorting and comparing multiple items. Learn more
Here's an example of how to create a relevance indicator:
RelevanceIndicator(
value: 15,
amount: 20,
)
Selectors
Lets the user choose a date.
There are three styles of MacosDatePickers
:
textual
: a text-only date picker where the user must select the day, month, or year and use the caret-control buttons to change the value. This is useful when space in your app is constrained.graphical
: a visual date picker where the user can navigate through a calendar-like interface to select a date.combined
: provides both textual
and graphical
interfaces.Example usage:
MacosDatePicker(
onDateChanged: (date) => debugPrint('$date'),
),
Lets the user choose a time.
There are three styles of MacosTimePickers
:
textual
: a text-only time picker where the user must select the hour or minute and use the caret-control buttons to change the value. This is useful when space in your app is constrained.graphical
: a visual time picker where the user can move the hands of a clock-like interface to select a time.combined
: provides both textual
and graphical
interfaces.Example usage:
MacosTimePicker(
onTimeChanged: (time) => debugPrint('$time'),
),
Lets the user choose a color via the native macOS color picker.
You can choose which mode to launch the picker in using the ColorPickerMode
enum. The default is ColorPickerMode.wheel
🚨 This widget will not work on platforms other than macOS!
Example usage:
MacosColorWell(
onColorSelected: (color) => debugPrint('$color'),
),
Run this command:
With Flutter:
$ flutter pub add macos_ui
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
macos_ui: ^1.7.5
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:macos_ui/macos_ui.dart';
import 'package:example/pages/buttons_page.dart';
import 'package:example/pages/colors_page.dart';
import 'package:example/pages/dialogs_page.dart';
import 'package:example/pages/fields_page.dart';
import 'package:example/pages/indicators_page.dart';
import 'package:example/pages/selectors_page.dart';
import 'package:example/pages/tabview_page.dart';
import 'package:example/pages/toolbar_page.dart';
import 'package:flutter/cupertino.dart';
import 'package:macos_ui/macos_ui.dart';
import 'package:provider/provider.dart';
import 'theme.dart';
void main() {
runApp(const MacosUIGalleryApp());
}
class MacosUIGalleryApp extends StatelessWidget {
const MacosUIGalleryApp({super.key});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AppTheme(),
builder: (context, _) {
final appTheme = context.watch<AppTheme>();
return MacosApp(
title: 'macos_ui Widget Gallery',
theme: MacosThemeData.light(),
darkTheme: MacosThemeData.dark(),
themeMode: appTheme.mode,
debugShowCheckedModeBanner: false,
home: const WidgetGallery(),
);
},
);
}
}
class WidgetGallery extends StatefulWidget {
const WidgetGallery({super.key});
@override
State<WidgetGallery> createState() => _WidgetGalleryState();
}
class _WidgetGalleryState extends State<WidgetGallery> {
double ratingValue = 0;
double sliderValue = 0;
bool value = false;
int pageIndex = 0;
late final searchFieldController = TextEditingController();
final List<Widget> pages = [
CupertinoTabView(
builder: (_) => const ButtonsPage(),
),
const IndicatorsPage(),
const FieldsPage(),
const ColorsPage(),
const Center(
child: MacosIcon(
CupertinoIcons.add,
),
),
const DialogsPage(),
const ToolbarPage(),
const SelectorsPage(),
const TabViewPage(),
];
@override
Widget build(BuildContext context) {
return PlatformMenuBar(
menus: const [
PlatformMenu(
label: 'macos_ui Widget Gallery',
menus: [
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.about,
),
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.quit,
),
],
),
PlatformMenu(
label: 'View',
menus: [
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.toggleFullScreen,
),
],
),
PlatformMenu(
label: 'Window',
menus: [
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.minimizeWindow,
),
PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.zoomWindow,
),
],
),
],
child: MacosWindow(
sidebar: Sidebar(
top: MacosSearchField(
placeholder: 'Search',
controller: searchFieldController,
onResultSelected: (result) {
switch (result.searchKey) {
case 'Buttons':
setState(() {
pageIndex = 0;
searchFieldController.clear();
});
break;
case 'Indicators':
setState(() {
pageIndex = 1;
searchFieldController.clear();
});
break;
case 'Fields':
setState(() {
pageIndex = 2;
searchFieldController.clear();
});
break;
case 'Colors':
setState(() {
pageIndex = 3;
searchFieldController.clear();
});
break;
case 'Dialogs and Sheets':
setState(() {
pageIndex = 5;
searchFieldController.clear();
});
break;
case 'Toolbar':
setState(() {
pageIndex = 6;
searchFieldController.clear();
});
break;
case 'Selectors':
setState(() {
pageIndex = 7;
searchFieldController.clear();
});
break;
default:
searchFieldController.clear();
}
},
results: const [
SearchResultItem('Buttons'),
SearchResultItem('Indicators'),
SearchResultItem('Fields'),
SearchResultItem('Colors'),
SearchResultItem('Dialogs and Sheets'),
SearchResultItem('Toolbar'),
SearchResultItem('Selectors'),
],
),
minWidth: 200,
builder: (context, controller) {
return SidebarItems(
currentIndex: pageIndex,
onChanged: (i) => setState(() => pageIndex = i),
scrollController: controller,
itemSize: SidebarItemSize.large,
items: [
const SidebarItem(
// leading: MacosIcon(CupertinoIcons.square_on_circle),
leading: MacosImageIcon(
AssetImage(
'assets/sf_symbols/button_programmable_2x.png',
),
),
label: Text('Buttons'),
),
const SidebarItem(
leading: MacosImageIcon(
AssetImage(
'assets/sf_symbols/lines_measurement_horizontal_2x.png',
),
),
label: Text('Indicators'),
),
const SidebarItem(
leading: MacosImageIcon(
AssetImage(
'assets/sf_symbols/character_cursor_ibeam_2x.png',
),
),
label: Text('Fields'),
),
SidebarItem(
leading: const MacosIcon(CupertinoIcons.folder),
label: const Text('Disclosure'),
trailing: Text(
'2',
style: TextStyle(
color: MacosTheme.brightnessOf(context) == Brightness.dark
? MacosColors.tertiaryLabelColor.darkColor
: MacosColors.tertiaryLabelColor,
),
),
disclosureItems: [
const SidebarItem(
leading: MacosImageIcon(
AssetImage(
'assets/sf_symbols/rectangle_3_group_2x.png',
),
),
label: Text('Colors'),
),
const SidebarItem(
leading: MacosIcon(CupertinoIcons.infinite),
label: Text('Item 3'),
),
],
),
const SidebarItem(
leading: MacosIcon(CupertinoIcons.square_on_square),
label: Text('Dialogs & Sheets'),
),
const SidebarItem(
leading: MacosIcon(CupertinoIcons.macwindow),
label: Text('Toolbar'),
),
const SidebarItem(
leading: MacosImageIcon(
AssetImage(
'assets/sf_symbols/filemenu_and_selection_2x.png',
),
),
label: Text('Selectors'),
),
const SidebarItem(
leading: MacosIcon(CupertinoIcons.uiwindow_split_2x1),
label: Text('TabView'),
),
],
);
},
bottom: const MacosListTile(
leading: MacosIcon(CupertinoIcons.profile_circled),
title: Text('Tim Apple'),
subtitle: Text('tim@apple.com'),
),
),
endSidebar: Sidebar(
startWidth: 200,
minWidth: 200,
maxWidth: 300,
shownByDefault: false,
builder: (context, scrollController) {
return const Center(
child: Text('End Sidebar'),
);
},
),
child: IndexedStack(
index: pageIndex,
children: pages,
),
),
);
}
}
Download Details:
Author:
Source Code: https://pub.dev/packages/macos_ui
1648208700
macos_ui
Flutter widgets and themes implementing the current macOS design language.
macOS welcomes contributions. Please see CONTRIBUTING.md for more information.
Layout
MacosWindow
is the basic frame for the macOS layout.
It has a Sidebar
on the left and the rest of the window is typically filled out with a MacosScaffold
. A scope for the MacosWindow
is provided by MacosWindowScope
. The sidebar can be toggled with MacosWindowScope.of(context).toggleSidebar()
. Please note that you must wrap your MacosScaffold
in a Builder
widget in order for this to work properly.
The MacosScaffold
is what you would call a "page".
The scaffold has a TitleBar
property and the children
property which accepts a ContentArea
widget and multiple ResizablePane
widgets. To catch navigation or routes below the scaffold, consider wrapping the MacosScaffold
in a CupertinoTabView
. By doing so, navigation inside the MacosScaffold
will be displayed inside the MacosScaffold
area instead of covering the entire window. To push a route outside a MacosScaffold
wrapped in a CupertinoTabView
, use the root navigator Navigator.of(context, rootNavigator: true)
See the documentation for customizations.
A new look for macOS apps was introduced in Big Sur (macOS 11). To match that look in your Flutter app, like our screenshots, your macos/Runner/MainFlutterWindow.swift
file should look like this.
import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
override func awakeFromNib() {
let flutterViewController = FlutterViewController.init()
let windowFrame = self.frame
self.contentViewController = flutterViewController
self.setFrame(windowFrame, display: true)
if #available(macOS 10.13, *) {
let customToolbar = NSToolbar()
customToolbar.showsBaselineSeparator = false
self.toolbar = customToolbar
}
self.titleVisibility = .hidden
self.titlebarAppearsTransparent = true
if #available(macOS 11.0, *) {
self.toolbarStyle = .unified
}
self.isMovableByWindowBackground = true
self.styleMask.insert(NSWindow.StyleMask.fullSizeContentView)
self.isOpaque = false
self.backgroundColor = .clear
let contentView = contentViewController!.view;
let superView = contentView.superview!;
let blurView = NSVisualEffectView()
blurView.frame = superView.bounds
blurView.autoresizingMask = [.width, .height]
blurView.blendingMode = NSVisualEffectView.BlendingMode.behindWindow
if #available(macOS 10.14, *) {
blurView.material = .underWindowBackground
}
superView.replaceSubview(contentView, with: blurView)
blurView.addSubview(contentView)
RegisterGeneratedPlugins(registry: flutterViewController)
super.awakeFromNib()
}
}
A widget that aims to approximate the [ListTile] widget found in Flutter's material library.
Usage:
MacosListTile(
leading: const Icon(CupertinoIcons.lightbulb),
title: Text(
'A robust library of Flutter components for macOS',
style: MacosTheme.of(context).typography.headline,
),
subtitle: Text(
'Create native looking macOS applications using Flutter',
style: MacosTheme.of(context).typography.subheadline.copyWith(
color: MacosColors.systemGrayColor,
),
),
),
Icons
A MacosIcon
is identical to a regular Icon
in every way with one exception - it respects a MacosTheme
. Use it the same way you would a regular icon:
MacosIcon(
CupertinoIcons.add,
// color: CupertinoColors.activeBlue.color,
// size: 20,
),
Buttons
A checkbox is a type of button that lets the user choose between two opposite states, actions, or values. A selected checkbox is considered on when it contains a checkmark and off when it's empty. A checkbox is almost always followed by a title unless it appears in a checklist. Learn more
Off | On | Mixed |
---|---|---|
Here's an example of how to create a basic checkbox:
bool selected = false;
MacosCheckbox(
value: selected,
onChanged: (value) {
setState(() => selected = value);
},
)
To make a checkbox in the mixed
state, set value
to null
.
A help button appears within a view and opens app-specific help documentation when clicked. All help buttons are circular, consistently sized buttons that contain a question mark icon. Learn more
Here's an example of how to create a help button:
HelpButton(
onPressed: () {
print('pressed help button'),
},
)
You can customize the help button appearance and behaviour using the HelpButtonTheme
, but it's not recommended by apple to change help button's appearance.
A radio button is a small, circular button followed by a title. Typically presented in groups of two to five, radio buttons provide the user a set of related but mutually exclusive choices. A radio button’s state is either on (a filled circle) or off (an empty circle). Learn more
Here's an example of how to create a basic radio button:
bool selected = false;
MacosRadioButton(
value: selected,
onChanged: (value) {
setState(() => selected = value);
},
),
A pop-up button (often referred to as a pop-up menu) is a type of button that, when clicked, displays a menu containing a list of mutually exclusive choices. The menu appears on top of the button. Like other types of menus, a pop-up button’s menu can include separators and symbols like checkmarks. After the menu is revealed, it remains open until the user chooses a menu item, clicks outside of the menu, switches to another app, or quits the app; or until the system displays an alert. Learn more
The type T
of the MacosPopupButton
is the type of the value that each pop-up menu item represents. All the entries in a given menu must represent values with consistent types. Typically, an enum
is used. Each MacosPopupMenuItem
in items must be specialized with that same type argument.
The onChanged
callback should update a state variable that defines the pop-up menu's value. It should also call State.setState
to rebuild the pop-up button with the new value.
When there are menu items that cannot be displayed within the available menu constraints, a caret is shown at the top or bottom of the open menu to signal that there are items that are not currently visible.
The menu can also be navigated with the up/down keys and an item selected with the Return key.
Dark Theme | Light Theme |
---|---|
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
Here's an example of how to create a basic pop-up button:
String popupValue = 'One';
MacosPopupButton<String>(
value: popupValue,
onChanged: (String? newValue) {
setState(() {
popupValue = newValue!;
});
},
items: <String>['One', 'Two', 'Three', 'Four']
.map<MacosPopupMenuItem<String>>((String value) {
return MacosPopupMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
A push button appears within a view and initiates an instantaneous app-specific action, such as printing a document or deleting a file. Push buttons contain text—not icons—and often open a separate window, dialog, or app so the user can complete a task. Learn more
Dark Theme | Light Theme |
---|---|
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
Here's an example of how to create a basic push button:
PushButton(
child: Text('button'),
buttonSize: ButtonSize.large,
onPressed: () {
print('button pressed');
},
),
A switch is a visual toggle between two mutually exclusive states — on and off. A switch shows that it's on when the accent color is visible and off when the switch appears colorless. Learn more
On | Off |
---|---|
![]() | ![]() |
Here's an example of how to create a basic toggle switch:
bool selected = false;
MacosSwitch(
value: selected,
onChanged: (value) {
setState(() => selected = value);
},
),
Dialogs and Sheets
Usage:
showMacosAlertDialog(
context: context,
builder: (_) => MacosAlertDialog(
appIcon: FlutterLogo(
size: 56,
),
title: Text(
'Alert Dialog with Primary Action',
style: MacosTheme.of(context).typography.headline,
),
message: Text(
'This is an alert dialog with a primary action and no secondary action',
textAlign: TextAlign.center,
style: MacosTheme.of(context).typography.headline,
),
primaryButton: PushButton(
buttonSize: ButtonSize.large,
child: Text('Primary'),
onPressed: () {},
),
),
);
Usage:
showMacosSheet(
context: context,
builder: (_) => const MacosuiSheet(),
);
Fields
A text field is a rectangular area in which the user enters or edits one or more lines of text. A text field can contain plain or styled text.
Here's an example of how to create a basic text field:
MacosTextField(),
Labels
Labels are a short description of what an element on the screen does.
Tooltips succinctly describe how to use controls without shifting people’s focus away from the primary interface. Help tags appear when the user positions the pointer over a control for a few seconds. A tooltip remains visible for 10 seconds, or until the pointer moves away from the control.
To create a tooltip, wrap any widget on a Tooltip
:
MacosTooltip(
message: 'This is a tooltip',
child: Text('Hover or long press to show a tooltip'),
),
You can customize the tooltip the way you want using its style
property. A tooltip automatically adapts to its environment, responding to touch and pointer events.
Indicators
Don’t make people sit around staring at a static screen waiting for your app to load content or perform lengthy data processing operations. Use progress indicators to let people know your app hasn't stalled and to give them some idea of how long they’ll be waiting.
Progress indicators have two distinct styles:
People don't interact with progress indicators; however, they are often accompanied by a button for canceling the corresponding operation. Learn more
A ProgressCircle
can be either determinate or indeterminate.
Determinate Progress Circle | Indeterminate Progress Circle |
---|---|
![]() | ![]() |
Here's an example of how to create an indeterminate progress circle:
ProgressCircle(
value: null,
),
You can provide a non-null value to value
to make the progress circle determinate.
A ProgressBar
can only be determinate.
Here's an example of how to create a determinate progress bar:
ProgressBar(
value: 30,
)
A level indicator graphically represents of a specific value within a range of numeric values. It’s similar to a slider in purpose, but more visual and doesn’t contain a distinct control for selecting a value—clicking and dragging across the level indicator itself to select a value is supported, however. A level indicator can also include tick marks, making it easy for the user to pinpoint a specific value in the range. There are three different level indicator styles, each with a different appearance, for communicating capacity, rating, and relevance.
A capacity indicator illustrates the current level in relation to a finite capacity. Capacity indicators are often used when communicating factors like disk and battery usage. Learn more
Continuous | Discrete |
---|---|
![]() | ![]() |
A horizontal translucent track that fills with a colored bar to indicate the current value. Tick marks are often displayed to provide context. | A horizontal row of separate, equally sized, rectangular segments. The number of segments matches the total capacity, and the segments fill completely—never partially—with color to indicate the current value. |
Here's an example of how to create an interactive continuous capacity indicator:
double value = 30;
CapacityIndicator(
value: value,
discrete: false,
onChanged: (v) {
setState(() => value = v);
},
),
You can set discrete
to true
to make it a discrete capacity indicator.
A rating indicator uses a series of horizontally arranged graphical symbols to communicate a ranking level. The default symbol is a star.
A rating indicator doesn’t display partial symbols—its value is rounded in order to display complete symbols only. Within a rating indicator, symbols are always the same distance apart and don't expand or shrink to fit the control. Learn more
Here's an example of how to create an interactive rating indicator:
double value = 3;
RatingIndicator(
amount: 5,
value: value,
onChanged: (v) {
setState(() => value = v);
}
)
A relevance indicator communicates relevancy using a series of vertical bars. It often appears in a list of search results for reference when sorting and comparing multiple items. Learn more
Here's an example of how to create a relevance indicator:
RelevanceIndicator(
value: 15,
amount: 20,
)
Author: GroovinChip
Source Code: https://github.com/GroovinChip/macos_ui
License: MIT License