Related
I want to do this:
This is the code from the video above:
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:pomodoro/5.hourglass_animation/countdown_timer/responsive_web.dart';
class StartPomodoro extends StatefulWidget {
const StartPomodoro({
super.key,
});
//final DateTime end;
#override
State<StartPomodoro> createState() => _StartPomodoroState();
}
class _StartPomodoroState extends State<StartPomodoro>
with TickerProviderStateMixin {
final now = DateTime.now();
List<bool> isSelected = [true, false];
late Timer timer;
late AnimationController controller;
String get countText {
Duration count = controller.duration! * controller.value;
return controller.isDismissed
? '${controller.duration!.inHours.toString().padLeft(2, '0')}:${(controller.duration!.inMinutes % 60).toString().padLeft(2, '0')}:${(controller.duration!.inSeconds % 60).toString().padLeft(2, '0')}'
: '${count.inHours.toString().padLeft(2, '0')}:${(count.inMinutes % 60).toString().padLeft(2, '0')}:${(count.inSeconds % 60).toString().padLeft(2, '0')}';
}
double progress = 1.0;
bool LongBreak = true;
void notify() {
if (countText == '00:00:00') {}
}
#override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 0),
);
controller.addListener(() {
notify();
if (controller.isAnimating) {
setState(() {
progress = controller.value;
});
} else {
setState(() {
progress = 1.0;
LongBreak = true;
});
}
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor:
LongBreak ? const Color(0xffD94530) : const Color(0xff6351c5),
body: GestureDetector(
onTap: () {
if (controller.isDismissed) {
showModalBottomSheet(
context: context,
builder: (context) => SizedBox(
height: 300,
child: CupertinoTimerPicker(
initialTimerDuration: controller.duration!,
onTimerDurationChanged: (time) {
setState(() {
controller.duration = time;
});
},
),
),
);
}
},
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Stack(
children: <Widget>[
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: const Color(0xffD94530),
height: controller.value * 580,
),
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
verticalDirection: VerticalDirection.up,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: ResponsiveWeb(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
vertical: 2.0, horizontal: 15.0),
child: Container(
width: MediaQuery.of(context).size.width,
height: 210,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: const Color(0xffFAFAFA)),
child: Container(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Column(
children: [
Text(
"Hyper-focused on... (+add task)",
style: GoogleFonts.nunito(
fontSize: 20.0,
fontWeight:
FontWeight.w500,
),
),
],
),
),
),
const SizedBox(height: 10),
Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
SingleChildScrollView(
scrollDirection:
Axis.horizontal,
child: Row(
mainAxisAlignment:
MainAxisAlignment
.center,
children: [
Padding(
padding:
const EdgeInsets
.fromLTRB(
2, 0, 2, 0),
child: Text(
countText,
style: GoogleFonts
.nunito(
fontWeight:
FontWeight
.w500,
letterSpacing: 8,
fontSize: 57.0,
color: const Color(
0xff3B3B3B),
),
),
),
],
),
),
SingleChildScrollView(
scrollDirection:
Axis.horizontal,
child: Row(
mainAxisAlignment:
MainAxisAlignment
.start,
textDirection:
TextDirection.ltr,
mainAxisSize:
MainAxisSize.max,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Padding(
padding:
const EdgeInsets
.fromLTRB(
13, 0, 26, 0),
child: Text(
'Hours',
style: GoogleFonts
.nunito(
fontWeight:
FontWeight
.w500,
// letterSpacing:
// 2,
fontSize: 20.0,
color: const Color(
0xff3B3B3B),
),
),
),
Padding(
padding:
const EdgeInsets
.fromLTRB(
13, 0, 26, 0),
child: Text(
'Minutes',
style: GoogleFonts
.nunito(
fontWeight:
FontWeight
.w500,
// letterSpacing:
// 2,
fontSize: 20.0,
color: const Color(
0xff3B3B3B),
),
),
),
Padding(
padding:
const EdgeInsets
.fromLTRB(
0, 0, 0, 0),
child: Text(
'Seconds',
style: GoogleFonts
.nunito(
fontWeight:
FontWeight
.w500,
// letterSpacing:
// 2,
fontSize: 20.0,
color: const Color(
0xff3B3B3B),
),
),
),
],
),
),
],
),
),
),
],
),
),
),
),
const SizedBox(
height: 65,
),
Column(
// mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 15.0),
child:
FloatingActionButton.extended(
elevation: 0,
backgroundColor:
const Color(0xffFAFAFA),
onPressed: () {
if (controller
.isAnimating) {
controller.stop();
setState(() {
LongBreak = false;
});
} else {
controller.reverse(
from: controller
.value ==
0
? 1.0
: controller
.value);
setState(() {
LongBreak = false;
});
}
},
icon: Icon(
controller.isAnimating
? Icons.pause_outlined
: Icons
.play_arrow_outlined,
size: 24,
color: const Color(
0xff3B3B3B),
),
label: Text(
controller.isAnimating
? "Pause"
: "Start",
style: GoogleFonts.nunito(
fontWeight:
FontWeight.w500,
letterSpacing: 2,
fontSize: 24.0,
color: const Color(
0xff3B3B3B),
),
)),
);
}),
],
),
],
),
),
),
],
),
],
);
}),
),
),
);
}
AnimationController _buildClockAnimation(TickerProvider tickerProvider) {
return AnimationController(
vsync: tickerProvider,
duration: const Duration(milliseconds: 750),
);
}
void _animateLeftDigit(
int prev,
int current,
AnimationController controller,
) {
final prevFirstDigit = (prev / 10).floor();
final currentFirstDigit = (current / 10).floor();
if (prevFirstDigit != currentFirstDigit) {
controller.forward();
}
}
}
And I decided to optimize the timer by adding a setting function. But it is difficult for me to add the animation, but the timer works fine. The only thing that doesn't work is the animation when I click “start”
This is what I mean:
Please click on the youtube video
https://www.youtube.com/watch?v=cuAS_Pk5cNk&ab_channel=lomipac
This is the code from the button of the second video above, where I want to initialize the animation:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../controllers/countdown_controller.dart';
class StartStopGroupButton extends StatefulWidget {
const StartStopGroupButton({Key? key}) : super(key: key);
#override
State<StartStopGroupButton> createState() => _StartStopGroupButtonState();
}
class _StartStopGroupButtonState extends State<StartStopGroupButton>
with TickerProviderStateMixin {
String startPausedText = 'Start'.tr;
String stopText = 'stop'.tr;
final CountDownController _countDownController = Get.find();
#override
Widget build(BuildContext context) {
return Obx(() => Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 15.0),
child: FloatingActionButton.extended(
heroTag: 'btn1',
elevation: 0,
backgroundColor: const Color(0xffFAFAFA),
onPressed: _countDownController.startPaused,
label: Text(
_countDownController.startPausedText.value,
style: GoogleFonts.nunito(
fontWeight: FontWeight.w500,
fontSize: 24.0,
color: const Color(0xff3B3B3B),
),
),
),
),
],
),
));
}
}
How can I link the animation to the start button from the second code?
Thanks for any help you can provide
I'm trying to implement a slider with arrow icons that allow the user to scroll the material table horizontally. I already did the slider component, but the scroll events in the arrows aren't working yet. I added a tableRef to the material table and tried to use tableEl.current.scrollTo() function, but, unfortunately, it isn't working. So How can I create the eventHandlers to scroll the table horizontally?
My custom material table
My slider component:
import React from 'react';
import ArrowBackIosIcon from '#material-ui/icons/ArrowBackIos';
import ArrowForwardIosIcon from '#material-ui/icons/ArrowForwardIos';
export function TableSlider({ onClickToRigth, onClickToLeft }) {
return (
<div style={{ zIndex: 1000, top: "39px", position: "absolute", width: "100%", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<ArrowBackIosIcon
onClick={onClickToLeft}
style={{ marginLeft: "4px", cursor: "pointer", opacity: "0.7" }}
/>
<ArrowForwardIosIcon
onClick={onClickToRigth}
style={{ cursor: "pointer", opacity: "0.8" }}
/>
</div>
)
}
My custom material table. Notice that I created a useRef and added it in the material table by doing: tableRef={tableEl}
import React, { useRef } from 'react';
import { Grid } from '#material-ui/core';
import MaterialTable from 'material-table';
import PropTypes from "prop-types";
import { MTableToolbar } from 'material-table';
import { injectIntl } from 'react-intl';
import { TableSlider } from '../table-slider';
function MyMaterialTable(props) {
const tableEl = useRef(null);
const { title, urledit, columns, data, options, deleteItem, rowClick, action } = props;
var opt = options;
if (opt == null) {
opt = {
sorting: true,
pageSize: 10,
showSelectAllCheckbox: true,
columnsButton: true,
toolbar: true,
minBodyHeight: 550,
paging: false,
headerStyle: {
backgroundColor: '#f9f9f9',
fontWeight: 'bold',
borderBottom: '2px solid #b3b3b3',
height: '100px'
}
};
}
opt.toolbar = false;
const handleDelete = (data, resolve) => {
deleteItem(data, resolve);
};
const scrollToRigth = () => {
console.log(tableEl.current)
// Can i use those functions with a useRef?
tableEl.current.scrollTo()
tableEl.current.scrollIntoView({ behavior: 'smooth', block: 'start' })
};
const scrollToLeft = () => {
// Can i use those functions with a useRef?
tableEl.current.scrollTo()
tableEl.current.scrollIntoView({ behavior: 'smooth', block: 'start' })
};
const intl = props.intl;
return (
<Grid container spacing={0} >
<Grid item xs={12} sm={12} style={{ position: "relative", display: 'table', tableLayout: 'fixed', width: '100%', minWidth: '210px', paddingLeft: 0, paddingRight: 0 }}>
<TableSlider onClickToLeft={scrollToLeft} onClickToRigth={scrollToRigth} />
<MaterialTable
title={title}
tableRef={tableEl}
id="material-table-id"
columns={columns}
data={data}
options={opt}
onRowClick={rowClick}
actions={action}
components={{
Toolbar: props => (
<div style={{ backgroundColor: '#e8eaf5', color: '#000000' }}>
<MTableToolbar {...props} />
</div>
),
}}
localization={{
grouping: {
groupedBy: intl.formatMessage({ id: "grouped.by" }),
placeholder: intl.formatMessage({ id: "headers.drap" })
},
pagination: {
labelDisplayedRows: '{from}-{to} ' + intl.formatMessage({ id: "of" }) + ' {count}',
labelRowsPerPage: intl.formatMessage({ id: "recordsPerPage" }),
labelRowsSelect: intl.formatMessage({ id: "records" })
},
toolbar: {
addRemoveColumns: intl.formatMessage({ id: "add.remove" }),
nRowsSelected: '{0}' + intl.formatMessage({ id: "rows.select" }),
showColumnsTitle: intl.formatMessage({ id: "show.columns" }),
showColumnsAriaLabel: intl.formatMessage({ id: "show.columns" }),
exportTitle: intl.formatMessage({ id: "export" }),
exportAriaLabel: intl.formatMessage({ id: "export" }),
exportName: intl.formatMessage({ id: "export.csv" }),
searchTooltip: intl.formatMessage({ id: "search" }),
searchPlaceholder: intl.formatMessage({ id: "search" })
},
header: {
actions: ''
},
body: {
emptyDataSourceMessage: intl.formatMessage({ id: "rows.show" }),
filterRow: {},
editRow: {
saveTooltip: intl.formatMessage({ id: "save" }),
cancelTooltip: intl.formatMessage({ id: "cancel" }),
deleteText: intl.formatMessage({ id: "sure.delete" })
},
addTooltip: intl.formatMessage({ id: "add" }),
deleteTooltip: intl.formatMessage({ id: "delete" }),
editTooltip: intl.formatMessage({ id: "update" })
}
}}
/>
</Grid>
</Grid>
);
}
export default injectIntl(MyMaterialTable);
MyMaterialTable.propTypes = {
title: PropTypes.string,
urledit: PropTypes.string,
columns: PropTypes.array,
data: PropTypes.array,
options: PropTypes.object,
deleteItem: PropTypes.func,
rowClick: PropTypes.func,
action: PropTypes.func
};
Here is my problem, I don't know how to use the ref to scroll my table horizontally. tableEl.current.scrollTo() and tableEl.current.scrollIntoView() returns undefined
const scrollToRigth = () => {
console.log(tableEl.current)
// Can i use those functions with a useRef?
tableEl.current.scrollTo()
tableEl.current.scrollIntoView({ behavior: 'smooth', block: 'start' })
};
const scrollToLeft = () => {
// Can i use those functions with a useRef?
tableEl.current.scrollTo()
tableEl.current.scrollIntoView({ behavior: 'smooth', block: 'start' })
};
I am using material-table in my React project. I have 3 levels of the data tree. Here it is the first one:
Is it possible when I click the first of the 2 items on 1st Level in data tree table to color it so it would be easier to see that values under it are child elements. Like this:
Also I would be even happier if it is possible to color it when I am passing data to it. Here it is how I am passing data:
data={[
{
id: 1, // MAIN ELEMENT
name: "Parent",
value: `Parent`,
},
{
id: 2, //CHILD OF THE MAIN ELEMENT
name: "Child",
value: `Child`,
parentId: 1,
}]}
Is there an option to color parent Element even before opening it, so it would be clear that it is PARENT and other is CHILD?
UPDATE:
Here is codesandbox example. As you can see when you open Parent1 Parent2 seems to be under Parent1. I want to make it clear that it is NOT under it.
https://codesandbox.io/s/jolly-germain-6fncr?file=/src/App.js
Let we talk about this problem first. It's neither programmatic nor css problem. It's just the problem how you show data, in other words, UX only.
There are several ways to achive, this is my work example: https://codesandbox.io/s/withered-dust-hb882?file=/src/App.js
Basically I just add one first column for parent only, that's it.
Ok, using CSS selectors it is not so easy to implement onExapnd color change. Here you will have to write check for parent TR check and sub Button rotate(90deg) check. To change the colors without onClick check you can use the following CSS:
tr[level="0"] {
background-color: #FF0000;
}
tr[level="1"] {
background-color: #FF0033;
}
tr[level="2"] {
background-color: #FF0066;
}
In JS way you can use the following code (of course you will have to add it in every table or extend the table or use util lib with ready rowStyle method..)
import React from "react";
import MaterialTable from "material-table";
import SearchIcon from "#material-ui/icons/Search";
import RotateLeftIcon from "#material-ui/icons/RotateLeft";
import { ArrowUpward, ChevronRight } from "#material-ui/icons";
//import './styles.css';
export default () => {
const constPathColors = {
1: '#FFFF00',
2: '#FFFF33',
3: '#FFFF66',
4: '#FFFF99',
5: '#FFFFCC'
};
return (
<MaterialTable
style={{ width: "100%", margin: "3%" }}
title="Income Statement"
icons={{
Filter: React.forwardRef((props, ref) => <SearchIcon ref={ref} />),
Search: React.forwardRef((props, ref) => <SearchIcon ref={ref} />),
ResetSearch: React.forwardRef((props, ref) => (
<RotateLeftIcon ref={ref} />
)),
SortArrow: ArrowUpward,
DetailPanel: ChevronRight
}}
columns={[
{
field: "name",
title: "Category"
},
{
field: "value",
title: "Value",
cellStyle: {
textAlign: "center"
}
}
]}
data={[
{
id: 1, // MAIN ELEMENT
name: "Parent 1",
value: `SomeParentValue`
},
{
id: 2, //CHILD OF THE MAIN ELEMENT
name: "Child 1-1",
value: `Child Value`,
parentId: 1
},
{
id: 3, //CHILD OF THE MAIN ELEMENT
name: "Child 1-2",
value: `Child Value`,
parentId: 1
},
{
id: 4, //CHILD OF THE CHILD ELEMENT
name: "Child 1-2-1",
value: `Child Value`,
parentId: 3
},
{
id: 5, // MAIN ELEMENT
name: "Parent 2",
value: `SomeParentValue`
}
]}
parentChildData={(row, rows) => rows.find(a => a.id === row.parentId)}
options={{
paging: false,
headerStyle: {
backgroundColor: "#378FC3",
color: "#FFF",
fontSize: "17px",
textAlign: "center",
fontWeight: "bold"
},
rowStyle: rowData => {
if(rowData.tableData.isTreeExpanded === false && rowData.tableData.path.length === 1) {
return {};
}
const rowBackgroundColor = constPathColors[rowData.tableData.path.length];
return {backgroundColor: rowBackgroundColor};
}
}}
/>
);
};
The row has default color before the expanding:
After expanding it has yellow (gradient depend on level) background color:
Thats how my tree view looks like. Thanks to the left: `var(--left-before, ${0}px), i could positioning the :befores wherever i want
https://i.ibb.co/Wp9XJcc/childscapture.png
viewTableTree.styles.js
import { makeStyles } from '#material-ui/core/styles';
export const useViewTableTreeStyles = makeStyles(theme => ({
root: {
'& .MuiPaper-root': {
boxShadow: 'none'
},
'& .MuiTable-root': {
position: 'relative',
overflow: 'hidden'
},
'& .MuiTableRow-root': {
'&:hover': { backgroundColor: 'rgba(0, 0, 0, 0.04)' },
'&:before': {
content: '""',
fontWeight: theme.font.weight.black,
fontSize: theme.font.size.xxl,
position: 'absolute',
left: `var(--left-before, ${0}px)`, //important trick here!
width: '1px',
height: '3.2rem',
backgroundColor: theme.palette.basic.bright
}
}
}
}));
then in the MaterialTable component
ViewTableTree.js
<div className={classes.root}>
<MaterialTable
icons={tableIcons}
data={rows}
columns={cells}
localization={{
header: {
actions: ''
}
}}
options={{
selection: false,
paging: false,
search: false,
showTitle: false,
toolbar: false,
actionsColumnIndex: -1,
rowStyle: rowData => {
let styles = { transition: 'transform 300ms' };
const levels = rowData.tableData.path.length === 1 ? 0 : rowData.tableData.path.length;
styles = { ...styles, '--left-before': `${levels * 6}px` };
return rowData.tableData.isTreeExpanded
? {
...styles,
fontWeight: 600,
backgroundColor: 'rgba(77, 93, 241, 0.08)'
}
: styles;
}
}}
{...props}
/>
</div>
I am making a sales invoice pdf using pdfmake. I want to put my company logo, and company details such as name, contact number, email, website etc in the header of the pdf document. I tried
header: "document header"
var docDefinition = {
header: 'simple text',
footer: {
columns: [
'Left part',
{ text: 'Right part', alignment: 'right' }
]
},
content: (...)
};
I can only add one pdfmake element. I want to add multiple-element in the header (and footer) of the document. Is it possible to add multiple-element? Is there any alternative way to achieve this?
[1] https://pdfmake.github.io/docs/document-definition-object/headers-footers/
I tried example from above url[1]. it doesn't mention multiple elements.
For adding multiple elements in header , you have to adjust page margin. It can be done as follow:
pageMargins: [ 40, 60, 40, 60 ],
You can change these values according to your requirements.
Just to throw this out there... I couldn't get the multi-element header to work with the example syntax on the pdf-make website. I think the custom header function requires a single-element return containing a columns array, not the content array itself.
docDefinition = {
header: function(currentPage, pageCount, pageSize) {
// computations...
return {
columns: [
{ text: 'My Title!', /* extra style attributes */},
{ text: 'My Subtitle!', /* extra style attributes */},
],
};
},
footer: 'blah blah blah',
content: [],
};
To add multiple elements (text, image, etc), you will need to add a customize function in your js. Example like below
customize: function (pdf) {
pdf['header']=(function() {
return {
columns: [
{
image: /*convert your image into base64 code and paste the code here to make the image work*/,
width: 10,
margin: [left, top, right, bottom]
},
{
text: ['Company Name\n Company Contact\n'],
bold: true,
alignment: 'center',
fontSize: 14,
margin: [L, T, R, B]
},
{
text: ['Company Email\n Company website\n'],
bold: true,
fontSize: 14,
margin: [L, T, R, B]
}
}
});
}
If you want to add for footer, you can just add another function for footer like
pdf['footer']=(function(){
{
text: ['Footer'],
bold: true,
fontSize: 14,
margin: [L, T, R, B]
}
});
I have a react native view i want to style dynamically.
The value of reaction will be sourced from an API, so i want to pass it into my styleheet
const Weather = ({ reaction, temperature }) => {
//const bg = `weatherconditions.${reaction}.color`
return (
<View
style={{ backgroundColor: weatherConditions[reaction].color }}>
The stylesheet looks like this
export const weatherConditions = {
Rain: {
color: '#005BEA',
title: 'Raining',
subtitle: 'Get a cup of coffee',
icon: 'weather-rainy'
},
Clear: {
color: '#f7b733',
title: 'So Sunny',
subtitle: 'It is hurting my eyes',
icon: 'weather-sunny'
},
Thunderstorm: {
color: '#616161',
title: 'A Storm is coming',
subtitle: 'Because Gods are angry',
icon: 'weather-lightning'
},
Clouds: {
color: '#1F1C2C',
title: 'Clouds',
subtitle: 'Everywhere',
icon: 'weather-cloudy'
},
Snow: {
color: '#00d2ff',
title: 'Snow',
subtitle: 'Get out and build a snowman for me',
icon: 'weather-snowy'
},
}
where either Clear, Rain, ThunderStorm can be the value of reaction
I want to dynamically provide the reaction value.
i have tried to do this
const Weather = ({ reaction, temperature }) => {
const bg = `weatherconditions.${reaction}.color`;
return (
<View
style={{ backgroundColor: bg }}
>
and
<View
style={{ backgroundColor: ${bg }}>
But none of them seem to work.
Any help solving this will be appreciated.
Not sure this is what you mean but hope it helps.
const styles = {
weather = reaction => ({
backgroundColor: reaction
})
}
And then in your <View/> tag provide the reaction
...
<View style={StyleSheet.flatten([styles.weather(reaction)])}>
//Your code here
</View>