blossom_tabs 4.0.0 blossom_tabs: ^4.0.0 copied to clipboard
Blossom Tab Manger Package for Flutter Blossom and related projects.
import 'dart:convert';
import 'dart:math';
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:blossom_tabs/blossom_tabs.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
doWhenWindowReady(() {
const initialSize = Size(800, 450);
appWindow.minSize = initialSize;
appWindow.size = initialSize;
appWindow.alignment = Alignment.center;
appWindow.show();
});
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
Widget buildTab(
BuildContext context, {
required bool isActive,
bool useRow = true,
Widget? icon,
Widget? activeIcon,
String? title,
TextStyle? style,
TextStyle? activeStyle,
}) {
var children = [
(isActive ? activeIcon ?? icon : icon) ??
const SizedBox(
width: 10,
),
if (title != null)
Flexible(
child: Text(
title,
softWrap: false,
overflow: TextOverflow.fade,
style: isActive ? activeStyle ?? style : style,
),
),
];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: useRow
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(children: children),
],
)
: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: children,
),
],
),
);
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _controller = BlossomTabController<int>(tabs: []);
var _tabs = <BlossomTab<int>>[];
BlossomTab<int> _getTab(String e) => BlossomTab<int>(
id: e,
data: int.parse(e.codeUnits.join()),
title: e.toUpperCase(),
isSticky: e == 'd',
);
@override
void initState() {
_tabs = ['a', 'b', 'c', 'd', 'e']
.map(
(e) => _getTab(e),
// BlossomTab.fromJson<int>(
// {
// "id": e,
// "data": {"value": int.parse(e.codeUnits.join())},
// "title": e.toUpperCase(),
// "isSticky": e == 'd' ? true : false,
// "maxWidth": 200.0,
// "stickyWidth": 50.0
// },
// (map) => map['value'],
// ),
)
.toList();
_controller = BlossomTabController<int>(currentTab: 'b', tabs: _tabs);
super.initState();
}
@override
Widget build(BuildContext context) {
return BlossomTabControllerScope(
controller: _controller,
child: Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(85),
child: Stack(
children: [
MoveWindow(
child: BlossomTabBar<int>(
height: 85,
bottomBarHeight: 40,
selectedColor: Colors.blue,
dragColor: Colors.blue.withOpacity(0.6),
stickyColor: Colors.white,
backgroundColor: Colors.blue.withOpacity(0.3),
dividerColor: Colors.blue,
bottomColor: Colors.blue,
margin: const EdgeInsets.only(left: 4, top: 4, right: 140),
tabBarMargin: 4,
tabBuilder: (context, tab, isActive) => buildTab(
context,
isActive: isActive,
title: tab.id,
activeStyle:
tab.id == 'd' ? null : const TextStyle(color: Colors.white),
icon: tab.id == 'd'
? null
: const Padding(
padding: EdgeInsets.all(4.0),
child: Icon(
Icons.ac_unit,
size: 14,
color: Colors.black26,
),
),
activeIcon: tab.id == 'd'
? null
: const Padding(
padding: EdgeInsets.all(8.0),
child: Icon(
Icons.ac_unit,
size: 14,
color: Colors.white,
),
),
),
tabActions: (context, tab) => [
if (tab.id != 'd')
Listener(
onPointerDown: (_) {
_controller.removeTabById(tab.id);
},
child: const Padding(
padding: EdgeInsets.all(4.0),
child: Icon(
Icons.close,
size: 14,
color: Colors.white,
),
),
),
],
bottomBar: BlossomTabControllerScopeDescendant<int>(
builder: (context, controller) {
// Future.delayed(Duration.zero)
// .then((_) => print(jsonEncode(controller.toJson())));
return Container(
color: controller.currentTab == 'd' ? Colors.white : null,
);
}),
actions: [
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: NewTabBtn(
onTap: () {
final z = _controller.tabs.map((e) => e.id).toList()..sort();
var c = z.isEmpty ? 'a' : z.last;
final lastCharacter =
String.fromCharCode(c.codeUnitAt(c.length - 1) + 1);
c = c.substring(0, c.length - 1) + lastCharacter;
_controller.addTab(_getTab(c));
},
),
)
],
),
),
Positioned(
right: 0,
child: WindowButtons(),
),
],
),
),
body: Row(
children: [
BlossomVerticalTabBar<int>(
width: 240,
sideBarWidth: 180,
selectedColor: Colors.blue,
dragColor: Colors.blue.withOpacity(0.6),
stickyColor: Colors.white,
backgroundColor: Colors.blue.withOpacity(0.3),
dividerColor: Colors.blue,
sideBarColor: Colors.blue,
margin: const EdgeInsets.only(left: 0, top: 0, right: 0, bottom: 40),
tabBarMargin: 0,
showIndicator: true,
indicatorColor: Colors.white,
tabBuilder: (context, tab, isActive) => buildTab(
context,
isActive: isActive,
useRow: false,
title: tab.id,
activeStyle: tab.id == 'd' ? null : const TextStyle(color: Colors.white),
activeIcon: tab.id == 'd'
? null
: const Padding(
padding: EdgeInsets.all(8.0),
child: Icon(
Icons.ac_unit,
size: 14,
color: Colors.white,
),
),
),
sideBar: BlossomTabControllerScopeDescendant<int>(
builder: (context, controller) {
// Future.delayed(Duration.zero)
// .then((_) => print(jsonEncode(controller.toJson())));
return Container(
color: controller.currentTab == 'd' ? Colors.white : null,
);
}),
actions: [
Padding(
padding: const EdgeInsets.only(top: 6.0),
child: NewTabBtn(
onTap: () {
final z = _controller.tabs.map((e) => e.id).toList()..sort();
var c = z.isEmpty ? 'a' : z.last;
final lastCharacter =
String.fromCharCode(c.codeUnitAt(c.length - 1) + 1);
c = c.substring(0, c.length - 1) + lastCharacter;
_controller.addTab(_getTab(c));
},
),
)
],
),
Expanded(
child: BlossomTabView<int>(
builder: (tab) => ColorBox(
child: Center(child: ColorBox(child: Center(child: Text(tab.id)))),
),
),
),
],
),
),
);
}
}
class NewTabBtn extends StatefulWidget {
const NewTabBtn({
Key? key,
required this.onTap,
}) : super(key: key);
final void Function() onTap;
@override
State<NewTabBtn> createState() => _NewTabBtnState();
}
class _NewTabBtnState extends State<NewTabBtn> {
var _opacity = 0.1;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: widget.onTap,
onHover: (h) => setState(() => _opacity = h ? 0.3 : 0.1),
child: Container(
padding: const EdgeInsets.all(2.0),
color: Colors.blue.withOpacity(_opacity),
child: const Icon(
Icons.add,
size: 22,
color: Colors.white,
),
),
);
}
}
class ColorBox extends StatefulWidget {
const ColorBox({Key? key, this.child}) : super(key: key);
final Widget? child;
@override
_ColorBoxState createState() => _ColorBoxState();
}
class _ColorBoxState extends State<ColorBox> {
Color? _color;
_randomColor() => Color(0xFF000000 + Random().nextInt(0x00FFFFFF));
@override
void initState() {
_color = _randomColor();
super.initState();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_color = _randomColor();
});
},
child: Container(width: 150, height: 150, color: _color, child: widget.child),
);
}
}
final buttonColors = WindowButtonColors(
iconNormal: Colors.blue,
mouseOver: Colors.blue.withOpacity(0.2),
mouseDown: Colors.blue,
);
final closeButtonColors = WindowButtonColors(
mouseOver: Colors.red.withOpacity(0.9),
mouseDown: Colors.red,
iconNormal: Colors.blue,
);
class WindowButtons extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
children: [
MinimizeWindowButton(colors: buttonColors),
MaximizeWindowButton(colors: buttonColors),
CloseWindowButton(colors: closeButtonColors),
],
);
}
}