Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
8bcad763
Commit
8bcad763
authored
Sep 24, 2015
by
Adam Barth
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Port Focus and Navigator-based widgets to fn3
parent
93ae1f28
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1077 additions
and
0 deletions
+1077
-0
dismissable.dart
packages/flutter/lib/src/fn3/dismissable.dart
+257
-0
focus.dart
packages/flutter/lib/src/fn3/focus.dart
+224
-0
framework.dart
packages/flutter/lib/src/fn3/framework.dart
+5
-0
navigator.dart
packages/flutter/lib/src/fn3/navigator.dart
+219
-0
progress_indicator.dart
packages/flutter/lib/src/fn3/progress_indicator.dart
+163
-0
radio.dart
packages/flutter/lib/src/fn3/radio.dart
+74
-0
switch.dart
packages/flutter/lib/src/fn3/switch.dart
+135
-0
No files found.
packages/flutter/lib/src/fn3/dismissable.dart
0 → 100644
View file @
8bcad763
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:sky'
as
sky
;
import
'package:sky/animation.dart'
;
import
'package:sky/src/fn3/basic.dart'
;
import
'package:sky/src/fn3/transitions.dart'
;
import
'package:sky/src/fn3/framework.dart'
;
import
'package:sky/src/fn3/gesture_detector.dart'
;
const
Duration
_kCardDismissFadeout
=
const
Duration
(
milliseconds:
200
);
const
Duration
_kCardDismissResize
=
const
Duration
(
milliseconds:
300
);
final
Interval
_kCardDismissResizeInterval
=
new
Interval
(
0.4
,
1.0
);
const
double
_kMinFlingVelocity
=
700.0
;
const
double
_kMinFlingVelocityDelta
=
400.0
;
const
double
_kFlingVelocityScale
=
1.0
/
300.0
;
const
double
_kDismissCardThreshold
=
0.4
;
enum
DismissDirection
{
vertical
,
horizontal
,
left
,
right
,
up
,
down
}
typedef
void
ResizedCallback
(
);
typedef
void
DismissedCallback
(
);
class
Dismissable
extends
StatefulComponent
{
Dismissable
({
Key
key
,
this
.
child
,
this
.
onResized
,
this
.
onDismissed
,
this
.
direction
:
DismissDirection
.
horizontal
})
:
super
(
key:
key
);
Widget
child
;
ResizedCallback
onResized
;
DismissedCallback
onDismissed
;
DismissDirection
direction
;
DismissableState
createState
()
=>
new
DismissableState
(
this
);
}
class
DismissableState
extends
ComponentState
<
Dismissable
>
{
DismissableState
(
Dismissable
config
)
:
super
(
config
)
{
_fadePerformance
=
new
AnimationPerformance
(
duration:
_kCardDismissFadeout
);
_fadePerformance
.
addStatusListener
((
AnimationStatus
status
)
{
if
(
status
==
AnimationStatus
.
completed
)
_handleFadeCompleted
();
});
}
AnimationPerformance
_fadePerformance
;
AnimationPerformance
_resizePerformance
;
Size
_size
;
double
_dragExtent
=
0.0
;
bool
_dragUnderway
=
false
;
bool
get
_directionIsYAxis
{
return
config
.
direction
==
DismissDirection
.
vertical
||
config
.
direction
==
DismissDirection
.
up
||
config
.
direction
==
DismissDirection
.
down
;
}
void
_handleFadeCompleted
()
{
if
(!
_dragUnderway
)
_startResizePerformance
();
}
bool
get
_isActive
{
return
_size
!=
null
&&
(
_dragUnderway
||
_fadePerformance
.
isAnimating
);
}
void
_maybeCallOnResized
()
{
if
(
config
.
onResized
!=
null
)
config
.
onResized
();
}
void
_maybeCallOnDismissed
()
{
if
(
config
.
onDismissed
!=
null
)
config
.
onDismissed
();
}
void
_startResizePerformance
()
{
assert
(
_size
!=
null
);
assert
(
_fadePerformance
!=
null
);
assert
(
_fadePerformance
.
isCompleted
);
assert
(
_resizePerformance
==
null
);
setState
(()
{
_resizePerformance
=
new
AnimationPerformance
()
..
duration
=
_kCardDismissResize
..
addListener
(
_handleResizeProgressChanged
);
_resizePerformance
.
play
();
});
}
void
_handleResizeProgressChanged
()
{
if
(
_resizePerformance
.
isCompleted
)
_maybeCallOnDismissed
();
else
_maybeCallOnResized
();
}
void
_handleDragStart
()
{
if
(
_fadePerformance
.
isAnimating
)
return
;
setState
(()
{
_dragUnderway
=
true
;
_dragExtent
=
0.0
;
_fadePerformance
.
progress
=
0.0
;
});
}
void
_handleDragUpdate
(
double
delta
)
{
if
(!
_isActive
||
_fadePerformance
.
isAnimating
)
return
;
double
oldDragExtent
=
_dragExtent
;
switch
(
config
.
direction
)
{
case
DismissDirection
.
horizontal
:
case
DismissDirection
.
vertical
:
_dragExtent
+=
delta
;
break
;
case
DismissDirection
.
up
:
case
DismissDirection
.
left
:
if
(
_dragExtent
+
delta
<
0
)
_dragExtent
+=
delta
;
break
;
case
DismissDirection
.
down
:
case
DismissDirection
.
right
:
if
(
_dragExtent
+
delta
>
0
)
_dragExtent
+=
delta
;
break
;
}
if
(
oldDragExtent
.
sign
!=
_dragExtent
.
sign
)
{
setState
(()
{
// Rebuild to update the new drag endpoint.
// The sign of _dragExtent is part of our build state;
// the actual value is not, it's just used to configure
// the performances.
});
}
if
(!
_fadePerformance
.
isAnimating
)
_fadePerformance
.
progress
=
_dragExtent
.
abs
()
/
(
_size
.
width
*
_kDismissCardThreshold
);
}
bool
_isFlingGesture
(
sky
.
Offset
velocity
)
{
double
vx
=
velocity
.
dx
;
double
vy
=
velocity
.
dy
;
if
(
_directionIsYAxis
)
{
if
(
vy
.
abs
()
-
vx
.
abs
()
<
_kMinFlingVelocityDelta
)
return
false
;
switch
(
config
.
direction
)
{
case
DismissDirection
.
vertical
:
return
vy
.
abs
()
>
_kMinFlingVelocity
;
case
DismissDirection
.
up
:
return
-
vy
>
_kMinFlingVelocity
;
default
:
return
vy
>
_kMinFlingVelocity
;
}
}
else
{
if
(
vx
.
abs
()
-
vy
.
abs
()
<
_kMinFlingVelocityDelta
)
return
false
;
switch
(
config
.
direction
)
{
case
DismissDirection
.
horizontal
:
return
vx
.
abs
()
>
_kMinFlingVelocity
;
case
DismissDirection
.
left
:
return
-
vx
>
_kMinFlingVelocity
;
default
:
return
vx
>
_kMinFlingVelocity
;
}
}
return
false
;
}
void
_handleDragEnd
(
sky
.
Offset
velocity
)
{
if
(!
_isActive
||
_fadePerformance
.
isAnimating
)
return
;
setState
(()
{
_dragUnderway
=
false
;
if
(
_fadePerformance
.
isCompleted
)
{
_startResizePerformance
();
}
else
if
(
_isFlingGesture
(
velocity
))
{
double
flingVelocity
=
_directionIsYAxis
?
velocity
.
dy
:
velocity
.
dx
;
_dragExtent
=
flingVelocity
.
sign
;
_fadePerformance
.
fling
(
velocity:
flingVelocity
.
abs
()
*
_kFlingVelocityScale
);
}
else
{
_fadePerformance
.
reverse
();
}
});
}
void
_handleSizeChanged
(
Size
newSize
)
{
setState
(()
{
_size
=
new
Size
.
copy
(
newSize
);
});
}
Point
get
_activeCardDragEndPoint
{
if
(!
_isActive
)
return
Point
.
origin
;
assert
(
_size
!=
null
);
double
extent
=
_directionIsYAxis
?
_size
.
height
:
_size
.
width
;
return
new
Point
(
_dragExtent
.
sign
*
extent
*
_kDismissCardThreshold
,
0.0
);
}
Widget
build
(
BuildContext
context
)
{
if
(
_resizePerformance
!=
null
)
{
AnimatedValue
<
double
>
squashAxisExtent
=
new
AnimatedValue
<
double
>(
_directionIsYAxis
?
_size
.
width
:
_size
.
height
,
end:
0.0
,
curve:
ease
,
interval:
_kCardDismissResizeInterval
);
return
new
SquashTransition
(
performance:
_resizePerformance
.
view
,
width:
_directionIsYAxis
?
squashAxisExtent
:
null
,
height:
!
_directionIsYAxis
?
squashAxisExtent
:
null
);
}
return
new
GestureDetector
(
onHorizontalDragStart:
_directionIsYAxis
?
null
:
_handleDragStart
,
onHorizontalDragUpdate:
_directionIsYAxis
?
null
:
_handleDragUpdate
,
onHorizontalDragEnd:
_directionIsYAxis
?
null
:
_handleDragEnd
,
onVerticalDragStart:
_directionIsYAxis
?
_handleDragStart
:
null
,
onVerticalDragUpdate:
_directionIsYAxis
?
_handleDragUpdate
:
null
,
onVerticalDragEnd:
_directionIsYAxis
?
_handleDragEnd
:
null
,
child:
new
SizeObserver
(
callback:
_handleSizeChanged
,
child:
new
FadeTransition
(
performance:
_fadePerformance
.
view
,
opacity:
new
AnimatedValue
<
double
>(
1.0
,
end:
0.0
),
child:
new
SlideTransition
(
performance:
_fadePerformance
.
view
,
position:
new
AnimatedValue
<
Point
>(
Point
.
origin
,
end:
_activeCardDragEndPoint
),
child:
config
.
child
)
)
)
);
}
}
packages/flutter/lib/src/fn3/focus.dart
0 → 100644
View file @
8bcad763
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:sky/src/fn3/framework.dart'
;
typedef
void
FocusChanged
(
GlobalKey
key
);
// _noFocusedScope is used by Focus to track the case where none of the Focus
// component's subscopes (e.g. dialogs) are focused. This is distinct from the
// focused scope being null, which means that we haven't yet decided which scope
// is focused and whichever is the first scope to ask for focus will get it.
final
GlobalKey
_noFocusedScope
=
new
GlobalKey
();
class
_FocusScope
extends
InheritedWidget
{
_FocusScope
({
Key
key
,
this
.
focusState
,
this
.
scopeFocused
:
true
,
// are we focused in our ancestor scope?
this
.
focusedScope
,
// which of our descendant scopes is focused, if any?
this
.
focusedWidget
,
Widget
child
})
:
super
(
key:
key
,
child:
child
);
final
bool
scopeFocused
;
final
FocusState
focusState
;
// These are mutable because we implicitly change them when they're null in
// certain cases, basically pretending retroactively that we were constructed
// with the right keys.
GlobalKey
focusedScope
;
GlobalKey
focusedWidget
;
// The ...IfUnset() methods don't need to notify descendants because by
// definition they are only going to make a change the very first time that
// our state is checked.
void
_setFocusedWidgetIfUnset
(
GlobalKey
key
)
{
focusState
.
_setFocusedWidgetIfUnset
(
key
);
focusedWidget
=
focusState
.
_focusedWidget
;
focusedScope
=
focusState
.
_focusedScope
==
_noFocusedScope
?
null
:
focusState
.
_focusedScope
;
}
void
_setFocusedScopeIfUnset
(
GlobalKey
key
)
{
focusState
.
_setFocusedScopeIfUnset
(
key
);
assert
(
focusedWidget
==
focusState
.
_focusedWidget
);
focusedScope
=
focusState
.
_focusedScope
==
_noFocusedScope
?
null
:
focusState
.
_focusedScope
;
}
bool
updateShouldNotify
(
_FocusScope
oldWidget
)
{
if
(
scopeFocused
!=
oldWidget
.
scopeFocused
)
return
true
;
if
(!
scopeFocused
)
return
false
;
if
(
focusedScope
!=
oldWidget
.
focusedScope
)
return
true
;
if
(
focusedScope
!=
null
)
return
false
;
if
(
focusedWidget
!=
oldWidget
.
focusedWidget
)
return
true
;
return
false
;
}
}
class
Focus
extends
StatefulComponent
{
Focus
({
GlobalKey
key
,
// key is required if this is a nested Focus scope
this
.
autofocus
:
false
,
this
.
child
})
:
super
(
key:
key
)
{
assert
(!
autofocus
||
key
!=
null
);
}
final
bool
autofocus
;
final
Widget
child
;
FocusState
createState
()
=>
new
FocusState
(
this
);
}
class
FocusState
extends
ComponentState
<
Focus
>
{
FocusState
(
Focus
config
)
:
super
(
config
);
GlobalKey
_focusedWidget
;
// when null, the first component to ask if it's focused will get the focus
GlobalKey
_currentlyRegisteredWidgetRemovalListenerKey
;
void
_setFocusedWidget
(
GlobalKey
key
)
{
setState
(()
{
_focusedWidget
=
key
;
if
(
_focusedScope
==
null
)
_focusedScope
=
_noFocusedScope
;
});
_updateWidgetRemovalListener
(
key
);
}
void
_setFocusedWidgetIfUnset
(
GlobalKey
key
)
{
if
(
_focusedWidget
==
null
&&
(
_focusedScope
==
null
||
_focusedScope
==
_noFocusedScope
))
{
_focusedWidget
=
key
;
_focusedScope
=
_noFocusedScope
;
_updateWidgetRemovalListener
(
key
);
}
}
void
_handleWidgetRemoved
(
GlobalKey
key
)
{
assert
(
_focusedWidget
==
key
);
_updateWidgetRemovalListener
(
null
);
setState
(()
{
_focusedWidget
=
null
;
});
}
void
_updateWidgetRemovalListener
(
GlobalKey
key
)
{
if
(
_currentlyRegisteredWidgetRemovalListenerKey
!=
key
)
{
if
(
_currentlyRegisteredWidgetRemovalListenerKey
!=
null
)
GlobalKey
.
unregisterRemoveListener
(
_currentlyRegisteredWidgetRemovalListenerKey
,
_handleWidgetRemoved
);
if
(
key
!=
null
)
GlobalKey
.
registerRemoveListener
(
key
,
_handleWidgetRemoved
);
_currentlyRegisteredWidgetRemovalListenerKey
=
key
;
}
}
GlobalKey
_focusedScope
;
// when null, the first scope to ask if it's focused will get the focus
GlobalKey
_currentlyRegisteredScopeRemovalListenerKey
;
void
_setFocusedScope
(
GlobalKey
key
)
{
setState
(()
{
_focusedScope
=
key
;
});
_updateScopeRemovalListener
(
key
);
}
void
_setFocusedScopeIfUnset
(
GlobalKey
key
)
{
if
(
_focusedScope
==
null
)
{
_focusedScope
=
key
;
_updateScopeRemovalListener
(
key
);
}
}
void
_scopeRemoved
(
GlobalKey
key
)
{
assert
(
_focusedScope
==
key
);
_currentlyRegisteredScopeRemovalListenerKey
=
null
;
setState
(()
{
_focusedScope
=
null
;
});
}
void
_updateScopeRemovalListener
(
GlobalKey
key
)
{
if
(
_currentlyRegisteredScopeRemovalListenerKey
!=
key
)
{
if
(
_currentlyRegisteredScopeRemovalListenerKey
!=
null
)
GlobalKey
.
unregisterRemoveListener
(
_currentlyRegisteredScopeRemovalListenerKey
,
_scopeRemoved
);
if
(
key
!=
null
)
GlobalKey
.
registerRemoveListener
(
key
,
_scopeRemoved
);
_currentlyRegisteredScopeRemovalListenerKey
=
key
;
}
}
void
initState
(
BuildContext
context
)
{
if
(
config
.
autofocus
)
FocusState
.
_moveScopeTo
(
context
,
config
);
_updateWidgetRemovalListener
(
_focusedWidget
);
_updateScopeRemovalListener
(
_focusedScope
);
}
void
dispose
()
{
_updateWidgetRemovalListener
(
null
);
_updateScopeRemovalListener
(
null
);
}
Widget
build
(
BuildContext
context
)
{
return
new
_FocusScope
(
focusState:
this
,
scopeFocused:
FocusState
.
_atScope
(
context
,
config
),
focusedScope:
_focusedScope
==
_noFocusedScope
?
null
:
_focusedScope
,
focusedWidget:
_focusedWidget
,
child:
config
.
child
);
}
static
bool
at
(
BuildContext
context
,
Widget
widget
,
{
bool
autofocus:
true
})
{
assert
(
widget
!=
null
);
assert
(
widget
.
key
is
GlobalKey
);
_FocusScope
focusScope
=
context
.
inheritedWidgetOfType
(
_FocusScope
);
if
(
focusScope
!=
null
)
{
if
(
autofocus
)
focusScope
.
_setFocusedWidgetIfUnset
(
widget
.
key
);
return
focusScope
.
scopeFocused
&&
focusScope
.
focusedScope
==
null
&&
focusScope
.
focusedWidget
==
widget
.
key
;
}
return
true
;
}
static
bool
_atScope
(
BuildContext
context
,
Widget
widget
,
{
bool
autofocus:
true
})
{
assert
(
widget
!=
null
);
_FocusScope
focusScope
=
context
.
inheritedWidgetOfType
(
_FocusScope
);
if
(
focusScope
!=
null
)
{
if
(
autofocus
)
focusScope
.
_setFocusedScopeIfUnset
(
widget
.
key
);
assert
(
widget
.
key
!=
null
);
return
focusScope
.
scopeFocused
&&
focusScope
.
focusedScope
==
widget
.
key
;
}
return
true
;
}
// Don't call moveTo() from your build() function, it's intended to be called
// from event listeners, e.g. in response to a finger tap or tab key.
static
void
moveTo
(
BuildContext
context
,
Widget
widget
)
{
assert
(
widget
!=
null
);
assert
(
widget
.
key
is
GlobalKey
);
_FocusScope
focusScope
=
context
.
inheritedWidgetOfType
(
_FocusScope
);
if
(
focusScope
!=
null
)
focusScope
.
focusState
.
_setFocusedWidget
(
widget
.
key
);
}
static
void
_moveScopeTo
(
BuildContext
context
,
Focus
component
)
{
assert
(
component
!=
null
);
assert
(
component
.
key
!=
null
);
_FocusScope
focusScope
=
context
.
inheritedWidgetOfType
(
_FocusScope
);
if
(
focusScope
!=
null
)
focusScope
.
focusState
.
_setFocusedScope
(
component
.
key
);
}
}
packages/flutter/lib/src/fn3/framework.dart
View file @
8bcad763
...
...
@@ -335,6 +335,11 @@ abstract class ComponentState<T extends StatefulComponent> {
/// additional state when the config field's value is changed.
void
didUpdateConfig
(
T
oldConfig
)
{
}
/// Called when this object is inserted into the tree. Override this function
/// to perform initialization that depends on the location at which this
/// object was inserted into the tree.
void
initState
(
BuildContext
context
)
{
}
/// Called when this object is removed from the tree. Override this to clean
/// up any resources allocated by this object.
void
dispose
()
{
}
...
...
packages/flutter/lib/src/fn3/navigator.dart
0 → 100644
View file @
8bcad763
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:sky/animation.dart'
;
import
'package:sky/src/fn3/basic.dart'
;
import
'package:sky/src/fn3/focus.dart'
;
import
'package:sky/src/fn3/framework.dart'
;
import
'package:sky/src/fn3/transitions.dart'
;
typedef
Widget
RouteBuilder
(
NavigatorState
navigator
,
RouteBase
route
);
typedef
void
NotificationCallback
(
);
abstract
class
RouteBase
{
AnimationPerformance
_performance
;
NotificationCallback
onDismissed
;
NotificationCallback
onCompleted
;
AnimationPerformance
createPerformance
()
{
AnimationPerformance
result
=
new
AnimationPerformance
(
duration:
transitionDuration
);
result
.
addStatusListener
((
AnimationStatus
status
)
{
switch
(
status
)
{
case
AnimationStatus
.
dismissed
:
if
(
onDismissed
!=
null
)
onDismissed
();
break
;
case
AnimationStatus
.
completed
:
if
(
onCompleted
!=
null
)
onCompleted
();
break
;
default
:
;
}
});
return
result
;
}
WatchableAnimationPerformance
ensurePerformance
({
Direction
direction
})
{
assert
(
direction
!=
null
);
if
(
_performance
==
null
)
_performance
=
createPerformance
();
AnimationStatus
desiredStatus
=
direction
==
Direction
.
forward
?
AnimationStatus
.
forward
:
AnimationStatus
.
reverse
;
if
(
_performance
.
status
!=
desiredStatus
)
_performance
.
play
(
direction
);
return
_performance
.
view
;
}
bool
get
isActuallyOpaque
=>
_performance
!=
null
&&
_performance
.
isCompleted
&&
isOpaque
;
bool
get
hasContent
=>
true
;
// set to false if you have nothing useful to return from build()
Duration
get
transitionDuration
;
bool
get
isOpaque
;
Widget
build
(
Key
key
,
NavigatorState
navigator
,
WatchableAnimationPerformance
performance
);
void
popState
([
dynamic
result
])
{
assert
(
result
==
null
);
}
String
toString
()
=>
'
$runtimeType
()'
;
}
const
Duration
_kTransitionDuration
=
const
Duration
(
milliseconds:
150
);
const
Point
_kTransitionStartPoint
=
const
Point
(
0.0
,
75.0
);
class
Route
extends
RouteBase
{
Route
({
this
.
name
,
this
.
builder
});
final
String
name
;
final
RouteBuilder
builder
;
bool
get
isOpaque
=>
true
;
Duration
get
transitionDuration
=>
_kTransitionDuration
;
Widget
build
(
Key
key
,
NavigatorState
navigator
,
WatchableAnimationPerformance
performance
)
{
// TODO(jackson): Hit testing should ignore transform
// TODO(jackson): Block input unless content is interactive
return
new
SlideTransition
(
key:
key
,
performance:
performance
,
position:
new
AnimatedValue
<
Point
>(
_kTransitionStartPoint
,
end:
Point
.
origin
,
curve:
easeOut
),
child:
new
FadeTransition
(
performance:
performance
,
opacity:
new
AnimatedValue
<
double
>(
0.0
,
end:
1.0
,
curve:
easeOut
),
child:
builder
(
navigator
,
this
)
)
);
}
String
toString
()
=>
'
$runtimeType
(name="
$name
")'
;
}
class
RouteState
extends
RouteBase
{
RouteState
({
this
.
callback
,
this
.
route
,
this
.
owner
});
Function
callback
;
RouteBase
route
;
StatefulComponent
owner
;
bool
get
isOpaque
=>
false
;
void
popState
([
dynamic
result
])
{
assert
(
result
==
null
);
if
(
callback
!=
null
)
callback
(
this
);
}
bool
get
hasContent
=>
false
;
Duration
get
transitionDuration
=>
const
Duration
();
Widget
build
(
Key
key
,
NavigatorState
navigator
,
WatchableAnimationPerformance
performance
)
=>
null
;
}
class
NavigatorHistory
{
NavigatorHistory
(
List
<
Route
>
routes
)
{
for
(
Route
route
in
routes
)
{
if
(
route
.
name
!=
null
)
namedRoutes
[
route
.
name
]
=
route
;
}
recents
.
add
(
routes
[
0
]);
}
List
<
RouteBase
>
recents
=
new
List
<
RouteBase
>();
int
index
=
0
;
Map
<
String
,
RouteBase
>
namedRoutes
=
new
Map
<
String
,
RouteBase
>();
RouteBase
get
currentRoute
=>
recents
[
index
];
bool
hasPrevious
()
=>
index
>
0
;
void
pushNamed
(
String
name
)
{
Route
route
=
namedRoutes
[
name
];
assert
(
route
!=
null
);
push
(
route
);
}
void
push
(
RouteBase
route
)
{
assert
(!
_debugCurrentlyHaveRoute
(
route
));
recents
.
insert
(
index
+
1
,
route
);
index
++;
}
void
pop
([
dynamic
result
])
{
if
(
index
>
0
)
{
RouteBase
route
=
recents
[
index
];
route
.
popState
(
result
);
index
--;
}
}
bool
_debugCurrentlyHaveRoute
(
RouteBase
route
)
{
return
recents
.
any
((
candidate
)
=>
candidate
==
route
);
}
}
class
Navigator
extends
StatefulComponent
{
Navigator
(
this
.
history
,
{
Key
key
})
:
super
(
key:
key
);
final
NavigatorHistory
history
;
NavigatorState
createState
()
=>
new
NavigatorState
(
this
);
}
class
NavigatorState
extends
ComponentState
<
Navigator
>
{
NavigatorState
(
Navigator
config
)
:
super
(
config
);
RouteBase
get
currentRoute
=>
config
.
history
.
currentRoute
;
void
pushState
(
StatefulComponent
owner
,
Function
callback
)
{
RouteBase
route
=
new
RouteState
(
owner:
owner
,
callback:
callback
,
route:
currentRoute
);
push
(
route
);
}
void
pushNamed
(
String
name
)
{
setState
(()
{
config
.
history
.
pushNamed
(
name
);
});
}
void
push
(
RouteBase
route
)
{
setState
(()
{
config
.
history
.
push
(
route
);
});
}
void
pop
([
dynamic
result
])
{
setState
(()
{
config
.
history
.
pop
(
result
);
});
}
Widget
build
(
BuildContext
context
)
{
List
<
Widget
>
visibleRoutes
=
new
List
<
Widget
>();
for
(
int
i
=
config
.
history
.
recents
.
length
-
1
;
i
>=
0
;
i
-=
1
)
{
RouteBase
route
=
config
.
history
.
recents
[
i
];
if
(!
route
.
hasContent
)
continue
;
WatchableAnimationPerformance
performance
=
route
.
ensurePerformance
(
direction:
(
i
<=
config
.
history
.
index
)
?
Direction
.
forward
:
Direction
.
reverse
);
route
.
onDismissed
=
()
{
setState
(()
{
assert
(
config
.
history
.
recents
.
contains
(
route
));
config
.
history
.
recents
.
remove
(
route
);
});
};
Key
key
=
new
ObjectKey
(
route
);
Widget
widget
=
route
.
build
(
key
,
this
,
performance
);
visibleRoutes
.
add
(
widget
);
if
(
route
.
isActuallyOpaque
)
break
;
}
if
(
visibleRoutes
.
length
>
1
)
{
visibleRoutes
.
insert
(
1
,
new
Listener
(
onPointerDown:
(
_
)
{
pop
();
},
child:
new
Container
()
));
}
return
new
Focus
(
child:
new
Stack
(
visibleRoutes
.
reversed
.
toList
()));
}
}
packages/flutter/lib/src/fn3/progress_indicator.dart
0 → 100644
View file @
8bcad763
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:math'
as
math
;
import
'dart:sky'
as
sky
;
import
'package:sky/animation.dart'
;
import
'package:sky/src/fn3/basic.dart'
;
import
'package:sky/src/fn3/theme.dart'
;
import
'package:sky/src/fn3/framework.dart'
;
import
'package:sky/src/fn3/transitions.dart'
;
const
double
_kLinearProgressIndicatorHeight
=
6.0
;
const
double
_kMinCircularProgressIndicatorSize
=
15.0
;
const
double
_kCircularProgressIndicatorStrokeWidth
=
3.0
;
abstract
class
ProgressIndicator
extends
StatefulComponent
{
ProgressIndicator
({
Key
key
,
this
.
value
,
this
.
bufferValue
})
:
super
(
key:
key
);
final
double
value
;
// Null for non-determinate progress indicator.
final
double
bufferValue
;
// TODO(hansmuller) implement the support for this.
Color
_getBackgroundColor
(
BuildContext
context
)
=>
Theme
.
of
(
context
).
primarySwatch
[
200
];
Color
_getValueColor
(
BuildContext
context
)
=>
Theme
.
of
(
context
).
primaryColor
;
Object
_getCustomPaintToken
(
double
performanceValue
)
=>
value
!=
null
?
value
:
performanceValue
;
Widget
_buildIndicator
(
BuildContext
context
,
double
performanceValue
);
ProgressIndicatorState
createState
()
=>
new
ProgressIndicatorState
(
this
);
}
class
ProgressIndicatorState
extends
ComponentState
<
ProgressIndicator
>
{
ProgressIndicatorState
(
ProgressIndicator
config
)
:
super
(
config
)
{
_performance
=
new
AnimationPerformance
()
..
duration
=
const
Duration
(
milliseconds:
1500
)
..
variable
=
new
AnimatedValue
<
double
>(
0.0
,
end:
1.0
,
curve:
ease
);
_performance
.
addStatusListener
((
AnimationStatus
status
)
{
if
(
status
==
AnimationStatus
.
completed
)
_restartAnimation
();
});
_performance
.
play
();
}
AnimationPerformance
_performance
;
double
get
_performanceValue
=>
(
_performance
.
variable
as
AnimatedValue
<
double
>).
value
;
void
_restartAnimation
()
{
_performance
.
progress
=
0.0
;
_performance
.
play
();
}
Widget
build
(
BuildContext
context
)
{
if
(
config
.
value
!=
null
)
return
config
.
_buildIndicator
(
context
,
_performanceValue
);
return
new
BuilderTransition
(
variables:
[
_performance
.
variable
],
performance:
_performance
.
view
,
builder:
(
BuildContext
context
)
{
return
config
.
_buildIndicator
(
context
,
_performanceValue
);
}
);
}
}
class
LinearProgressIndicator
extends
ProgressIndicator
{
LinearProgressIndicator
({
Key
key
,
double
value
,
double
bufferValue
})
:
super
(
key:
key
,
value:
value
,
bufferValue:
bufferValue
);
void
_paint
(
BuildContext
context
,
double
performanceValue
,
sky
.
Canvas
canvas
,
Size
size
)
{
Paint
paint
=
new
Paint
()
..
color
=
_getBackgroundColor
(
context
)
..
setStyle
(
sky
.
PaintingStyle
.
fill
);
canvas
.
drawRect
(
Point
.
origin
&
size
,
paint
);
paint
.
color
=
_getValueColor
(
context
);
if
(
value
!=
null
)
{
double
width
=
value
.
clamp
(
0.0
,
1.0
)
*
size
.
width
;
canvas
.
drawRect
(
Point
.
origin
&
new
Size
(
width
,
size
.
height
),
paint
);
}
else
{
double
startX
=
size
.
width
*
(
1.5
*
performanceValue
-
0.5
);
double
endX
=
startX
+
0.5
*
size
.
width
;
double
x
=
startX
.
clamp
(
0.0
,
size
.
width
);
double
width
=
endX
.
clamp
(
0.0
,
size
.
width
)
-
x
;
canvas
.
drawRect
(
new
Point
(
x
,
0.0
)
&
new
Size
(
width
,
size
.
height
),
paint
);
}
}
Widget
_buildIndicator
(
BuildContext
context
,
double
performanceValue
)
{
return
new
Container
(
constraints:
new
BoxConstraints
.
tightFor
(
width:
double
.
INFINITY
,
height:
_kLinearProgressIndicatorHeight
),
child:
new
CustomPaint
(
token:
_getCustomPaintToken
(
performanceValue
),
callback:
(
sky
.
Canvas
canvas
,
Size
size
)
{
_paint
(
context
,
performanceValue
,
canvas
,
size
);
}
)
);
}
}
class
CircularProgressIndicator
extends
ProgressIndicator
{
static
const
_kTwoPI
=
math
.
PI
*
2.0
;
static
const
_kEpsilon
=
.
0000001
;
// Canavs.drawArc(r, 0, 2*PI) doesn't draw anything, so just get close.
static
const
_kSweep
=
_kTwoPI
-
_kEpsilon
;
static
const
_kStartAngle
=
-
math
.
PI
/
2.0
;
CircularProgressIndicator
({
Key
key
,
double
value
,
double
bufferValue
})
:
super
(
key:
key
,
value:
value
,
bufferValue:
bufferValue
);
void
_paint
(
BuildContext
context
,
double
performanceValue
,
sky
.
Canvas
canvas
,
Size
size
)
{
Paint
paint
=
new
Paint
()
..
color
=
_getValueColor
(
context
)
..
strokeWidth
=
_kCircularProgressIndicatorStrokeWidth
..
setStyle
(
sky
.
PaintingStyle
.
stroke
);
if
(
value
!=
null
)
{
double
angle
=
value
.
clamp
(
0.0
,
1.0
)
*
_kSweep
;
sky
.
Path
path
=
new
sky
.
Path
()
..
arcTo
(
Point
.
origin
&
size
,
_kStartAngle
,
angle
,
false
);
canvas
.
drawPath
(
path
,
paint
);
}
else
{
double
startAngle
=
_kTwoPI
*
(
1.75
*
performanceValue
-
0.75
);
double
endAngle
=
startAngle
+
_kTwoPI
*
0.75
;
double
arcAngle
=
startAngle
.
clamp
(
0.0
,
_kTwoPI
);
double
arcSweep
=
endAngle
.
clamp
(
0.0
,
_kTwoPI
)
-
arcAngle
;
sky
.
Path
path
=
new
sky
.
Path
()
..
arcTo
(
Point
.
origin
&
size
,
_kStartAngle
+
arcAngle
,
arcSweep
,
false
);
canvas
.
drawPath
(
path
,
paint
);
}
}
Widget
_buildIndicator
(
BuildContext
context
,
double
performanceValue
)
{
return
new
Container
(
constraints:
new
BoxConstraints
(
minWidth:
_kMinCircularProgressIndicatorSize
,
minHeight:
_kMinCircularProgressIndicatorSize
),
child:
new
CustomPaint
(
token:
_getCustomPaintToken
(
performanceValue
),
callback:
(
sky
.
Canvas
canvas
,
Size
size
)
{
_paint
(
context
,
performanceValue
,
canvas
,
size
);
}
)
);
}
}
packages/flutter/lib/src/fn3/radio.dart
0 → 100644
View file @
8bcad763
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:sky'
as
sky
;
import
'package:sky/src/fn3/basic.dart'
;
import
'package:sky/src/fn3/framework.dart'
;
import
'package:sky/src/fn3/gesture_detector.dart'
;
import
'package:sky/src/fn3/theme.dart'
;
const
sky
.
Color
_kLightOffColor
=
const
sky
.
Color
(
0x8A000000
);
const
sky
.
Color
_kDarkOffColor
=
const
sky
.
Color
(
0xB2FFFFFF
);
typedef
RadioValueChanged
(
Object
value
);
class
Radio
extends
StatefulComponent
{
Radio
({
Key
key
,
this
.
value
,
this
.
groupValue
,
this
.
onChanged
})
:
super
(
key:
key
)
{
assert
(
onChanged
!=
null
);
}
final
Object
value
;
final
Object
groupValue
;
final
RadioValueChanged
onChanged
;
RadioState
createState
()
=>
new
RadioState
(
this
);
}
class
RadioState
extends
ComponentState
<
Radio
>
{
RadioState
(
Radio
config
)
:
super
(
config
);
Color
_getColor
(
BuildContext
context
)
{
ThemeData
themeData
=
Theme
.
of
(
context
);
if
(
config
.
value
==
config
.
groupValue
)
return
themeData
.
accentColor
;
return
themeData
.
brightness
==
ThemeBrightness
.
light
?
_kLightOffColor
:
_kDarkOffColor
;
}
Widget
build
(
BuildContext
context
)
{
const
double
kDiameter
=
16.0
;
const
double
kOuterRadius
=
kDiameter
/
2
;
const
double
kInnerRadius
=
5.0
;
return
new
GestureDetector
(
onTap:
()
=>
config
.
onChanged
(
config
.
value
),
child:
new
Container
(
margin:
const
EdgeDims
.
symmetric
(
horizontal:
5.0
),
width:
kDiameter
,
height:
kDiameter
,
child:
new
CustomPaint
(
callback:
(
sky
.
Canvas
canvas
,
Size
size
)
{
Paint
paint
=
new
Paint
()..
color
=
_getColor
(
context
);
// Draw the outer circle
paint
.
setStyle
(
sky
.
PaintingStyle
.
stroke
);
paint
.
strokeWidth
=
2.0
;
canvas
.
drawCircle
(
const
Point
(
kOuterRadius
,
kOuterRadius
),
kOuterRadius
,
paint
);
// Draw the inner circle
if
(
config
.
value
==
config
.
groupValue
)
{
paint
.
setStyle
(
sky
.
PaintingStyle
.
fill
);
canvas
.
drawCircle
(
const
Point
(
kOuterRadius
,
kOuterRadius
),
kInnerRadius
,
paint
);
}
}
)
)
);
}
}
packages/flutter/lib/src/fn3/switch.dart
0 → 100644
View file @
8bcad763
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:sky'
as
sky
;
import
'package:sky/material.dart'
;
import
'package:sky/painting.dart'
;
import
'package:sky/rendering.dart'
;
import
'package:sky/src/fn3/basic.dart'
;
import
'package:sky/src/fn3/theme.dart'
;
import
'package:sky/src/fn3/framework.dart'
;
export
'package:sky/rendering.dart'
show
ValueChanged
;
const
sky
.
Color
_kThumbOffColor
=
const
sky
.
Color
(
0xFFFAFAFA
);
const
sky
.
Color
_kTrackOffColor
=
const
sky
.
Color
(
0x42000000
);
const
double
_kSwitchWidth
=
35.0
;
const
double
_kThumbRadius
=
10.0
;
const
double
_kSwitchHeight
=
_kThumbRadius
*
2.0
;
const
double
_kTrackHeight
=
14.0
;
const
double
_kTrackRadius
=
_kTrackHeight
/
2.0
;
const
double
_kTrackWidth
=
_kSwitchWidth
-
(
_kThumbRadius
-
_kTrackRadius
)
*
2.0
;
const
Duration
_kCheckDuration
=
const
Duration
(
milliseconds:
200
);
const
Size
_kSwitchSize
=
const
Size
(
_kSwitchWidth
+
2.0
,
_kSwitchHeight
+
2.0
);
const
double
_kReactionRadius
=
_kSwitchWidth
/
2.0
;
class
Switch
extends
LeafRenderObjectWidget
{
Switch
({
Key
key
,
this
.
value
,
this
.
onChanged
})
:
super
(
key:
key
);
final
bool
value
;
final
ValueChanged
onChanged
;
_RenderSwitch
createRenderObject
()
=>
new
_RenderSwitch
(
value:
value
,
thumbColor:
null
,
onChanged:
onChanged
);
void
updateRenderObject
(
_RenderSwitch
renderObject
,
Switch
oldWidget
)
{
renderObject
.
value
=
value
;
renderObject
.
onChanged
=
onChanged
;
// TODO(abarth): How do we get the current theme here?
// renderObject.thumbColor = Theme.of(this).accentColor;
}
}
class
_RenderSwitch
extends
RenderToggleable
{
_RenderSwitch
({
bool
value
,
Color
thumbColor:
_kThumbOffColor
,
ValueChanged
onChanged
})
:
_thumbColor
=
thumbColor
,
super
(
value:
value
,
onChanged:
onChanged
,
size:
_kSwitchSize
)
{}
Color
_thumbColor
;
Color
get
thumbColor
=>
_thumbColor
;
void
set
thumbColor
(
Color
value
)
{
if
(
value
==
_thumbColor
)
return
;
_thumbColor
=
value
;
markNeedsPaint
();
}
RadialReaction
_radialReaction
;
void
handleEvent
(
sky
.
Event
event
,
BoxHitTestEntry
entry
)
{
if
(
event
is
sky
.
PointerEvent
)
{
if
(
event
.
type
==
'pointerdown'
)
_showRadialReaction
(
entry
.
localPosition
);
else
if
(
event
.
type
==
'pointerup'
)
_hideRadialReaction
();
}
super
.
handleEvent
(
event
,
entry
);
}
void
_showRadialReaction
(
Point
startLocation
)
{
if
(
_radialReaction
!=
null
)
return
;
_radialReaction
=
new
RadialReaction
(
center:
new
Point
(
_kSwitchSize
.
width
/
2.0
,
_kSwitchSize
.
height
/
2.0
),
radius:
_kReactionRadius
,
startPosition:
startLocation
)
..
addListener
(
markNeedsPaint
)
..
show
();
}
Future
_hideRadialReaction
()
async
{
if
(
_radialReaction
==
null
)
return
;
await
_radialReaction
.
hide
();
_radialReaction
=
null
;
}
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
final
PaintingCanvas
canvas
=
context
.
canvas
;
sky
.
Color
thumbColor
=
_kThumbOffColor
;
sky
.
Color
trackColor
=
_kTrackOffColor
;
if
(
value
)
{
thumbColor
=
_thumbColor
;
trackColor
=
new
sky
.
Color
(
_thumbColor
.
value
&
0x80FFFFFF
);
}
// Draw the track rrect
sky
.
Paint
paint
=
new
sky
.
Paint
()
..
color
=
trackColor
..
style
=
sky
.
PaintingStyle
.
fill
;
sky
.
Rect
rect
=
new
sky
.
Rect
.
fromLTWH
(
offset
.
dx
,
offset
.
dy
+
_kSwitchHeight
/
2.0
-
_kTrackHeight
/
2.0
,
_kTrackWidth
,
_kTrackHeight
);
sky
.
RRect
rrect
=
new
sky
.
RRect
()
..
setRectXY
(
rect
,
_kTrackRadius
,
_kTrackRadius
);
canvas
.
drawRRect
(
rrect
,
paint
);
if
(
_radialReaction
!=
null
)
_radialReaction
.
paint
(
canvas
,
offset
);
// Draw the raised thumb with a shadow
paint
.
color
=
thumbColor
;
ShadowDrawLooperBuilder
builder
=
new
ShadowDrawLooperBuilder
();
for
(
BoxShadow
boxShadow
in
shadows
[
1
])
builder
.
addShadow
(
boxShadow
.
offset
,
boxShadow
.
color
,
boxShadow
.
blur
);
paint
.
drawLooper
=
builder
.
build
();
// The thumb contracts slightly during the animation
double
inset
=
2.0
-
(
position
.
value
-
0.5
).
abs
()
*
2.0
;
Point
thumbPos
=
new
Point
(
offset
.
dx
+
_kTrackRadius
+
position
.
value
*
(
_kTrackWidth
-
_kTrackRadius
*
2
),
offset
.
dy
+
_kSwitchHeight
/
2.0
);
canvas
.
drawCircle
(
thumbPos
,
_kThumbRadius
-
inset
,
paint
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment