Compare commits

..

5 Commits

Author SHA1 Message Date
Luke 35887faf50 introduce fluro native transition for android - more closely matches android animation 2018-04-05 16:55:19 -07:00
Luke 9dcec93b4a reformat code 2018-04-05 14:32:06 -07:00
Luke a48b722468 fix warnings 2018-04-05 14:09:47 -07:00
Luke 9f7f680d4e tidying 2018-04-05 14:07:43 -07:00
Luke ab8ef67243 wip - routable lifecycle 2018-03-28 12:52:50 -07:00
46 changed files with 506 additions and 822 deletions

View File

@ -1,38 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -1,18 +0,0 @@
---
name: I need help using this library or have a question
about: Please, strongly consider posting your question to Stack Overflow or another
place. The purpose of this issue tracker is to track bugs and feature requests.
title: ''
labels: question, stack overflow
assignees: ''
---
Please, strongly consider posting your question to Stack Overflow. The purpose of this issue tracker is to track bugs and feature requests. Questions on how to use the library should be posted to stack overflow so that everyone can benefit from your question.
If you really need to post your question here:
1. Please be super clear on what you're trying to achieve. What is the expected result?
2. Please outline what you've tried. There is no point us suggesting something you've already tried.
3. Outline the things that have failed, based on your past attempts. This will help us to diagnose whether we need to add a feature or whether it is a bug.
Thanks!

5
.gitignore vendored
View File

@ -9,8 +9,3 @@
pubspec.lock
coverage
__temp_coverage*
.dart_tool/
build/
# iOS
**/flutter_export_environment.sh

View File

@ -1,30 +1,21 @@
os:
- linux
sudo: false
addons:
apt:
# Flutter depends on /usr/lib/x86_64-linux-gnu/libstdc++.so.6 version GLIBCXX_3.4.18
sources:
- ubuntu-toolchain-r-test
- ubuntu-toolchain-r-test # if we don't specify this, the libstdc++6 we get is the wrong version
packages:
- libstdc++6
- fonts-droid
before_script:
- ./scripts/travis_setup.sh
- ./flutter/bin/flutter doctor
script:
- ./flutter/bin/flutter test --coverage
after_success:
- bash <(curl -s https://codecov.io/bash) -t $CODE_COV_TOKEN
cache:
directories:
- $HOME/.pub-cache
env:
- FLUTTER_VERSION=dev
matrix:
allow_failures:
- env: FLUTTER_VERSION=dev
before_script:
- git clone https://github.com/flutter/flutter.git -b $FLUTTER_VERSION
- $TRAVIS_BUILD_DIR/flutter/bin/flutter doctor
script:
- ./tool/travis.sh
after_success:
- bash <(curl -s https://codecov.io/bash) -t $CODE_COV_TOKEN
- $HOME/.pub-cache

View File

@ -1,58 +1,3 @@
# 1.6.3
- Remove upper bounds on Flutter SDK checks because Flutter releases are a ridiculous mess
# 1.6.2
- Support for Flutter `>=1.12 <=1.17`
# 1.6.1
- Support for Flutter `1.12+`
# 1.6.0
- No changes other than fixes for non-backwards compatible Flutter changes
- Flutter `>= 1.12.0` is required due to Flutter compatibility issues
- Dart `>= 2.6.0` is required
# 1.5.2
- Remove dependency on `dart:io`
- 1.5.x and lower now only supports Flutter versions `< 1.13.0`
# 1.5.1
- Add explicit material and full screen material transition types
- Fix issue in transition logic
- Remove redundant `new`, `const`, etc qualifiers
- Tidy example
- Add font license info
# 1.5.0
- Native transitions will now use the Cupertino page route on iOS and Material page route on android. This will enable swipe gestures on iOS.
- Added cupertino specific transition types.
- **You should not be using Cupertino types on non-iOS platforms. It's up to you, but it's bad design**.
# 1.4.0
- Added the ability to define a transition at the point of route definition. Route transitions are optional and any transition defined a "push" will override the route definition.
# 1.3.7
- Add `toString` for custom `RouteNotFoundException` type
# 1.3.6
- Small fix to error return type when no route match was made
# 1.3.5
- add `pop` convenience
- add `clearStack` flag so that you can clear the history when pushing a route
# 1.3.4
- Change lower dart version to cater to older flutter versions
# 1.3.3
- Fix analyzer issues
- Remove deprecations in example code
- Fix pubspec analysis issue
# 1.3.2
- Dart 2 package (pubspec) compliance changes ONLY
- **Note**: No functional changes
# 1.3.1
- Fixes an issue with the route generator (result cannot be Null)

16
LICENSE
View File

@ -1,9 +1,9 @@
Fluro
Created by Yakka
https://theyakka.com
Created by Posse in NYC
http://goposse.com
Copyright (c) 2019 Yakka LLC.
Copyright (c) 2017 Posse Productions LLC.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -14,17 +14,17 @@ modification, are permitted provided that the following conditions are met:
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the Yakka LLC, Yakka nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
* Neither the name of the Posse Productions LLC, Posse nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL YAKKA LLC (YAKKA) BE LIABLE FOR ANY
DISCLAIMED. IN NO EVENT SHALL POSSE PRODUCTIONS LLC (POSSE) BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,13 +1,11 @@
<img src="https://storage.googleapis.com/product-logos/logo_fluro.png" width="220">
<img src="https://storage.googleapis.com/app-logos/logo_fluro.png" width="220">
<br/><br/>
The brightest, hippest, coolest router for Flutter.
[![Version](https://img.shields.io/badge/version-1.6.3-blue.svg)](https://pub.dartlang.org/packages/fluro)
[![Build Status](https://travis-ci.org/theyakka/fluro.svg?branch=master)](https://travis-ci.org/theyakka/fluro)
[![Coverage](https://codecov.io/gh/theyakka/fluro/branch/master/graph/badge.svg)](https://codecov.io/gh/theyakka/fluro)
Version `1.6.0` (and higher) requires Flutter `>= 1.12.0` and Dart `>= 2.6.0`. If you're running an older version of Flutter, use a version `< 1.6.0`.
[![Version](https://img.shields.io/badge/version-1.3.1-blue.svg)](https://pub.dartlang.org/packages/fluro)
[![Build Status](https://travis-ci.org/goposse/fluro.svg?branch=master)](https://travis-ci.org/goposse/fluro)
[![Coverage](https://codecov.io/gh/goposse/fluro/branch/master/graph/badge.svg)](https://codecov.io/gh/goposse/fluro)
## Features
@ -27,14 +25,14 @@ See CHANGELOG for all breaking (and non-breaking) changes.
You should ensure that you add the router as a dependency in your flutter project.
```yaml
dependencies:
fluro: "^1.6.3"
fluro: "^1.3.1"
```
You can also reference the git repo directly if you want:
```yaml
dependencies:
fluro:
git: git://github.com/theyakka/fluro.git
git: git://github.com/goposse/fluro.git
```
@ -48,22 +46,19 @@ There is a pretty sweet example project in the `example` folder. Check it out. O
First, you should define a new `Router` object by initializing it as such:
```dart
final router = Router();
final router = new Router();
```
It may be convenient for you to store the router globally/statically so that
you can access the router in other areas in your application.
After instantiating the router, you will need to define your routes and your route handlers:
```dart
var usersHandler = Handler(handlerFunc: (BuildContext context, Map<String, dynamic> params) {
return UsersScreen(params["id"][0]);
var usersHandler = new Handler(handlerFunc: (BuildContext context, Map<String, dynamic> params) {
return new UsersScreen(params["id"][0]);
});
void defineRoutes(Router router) {
router.define("/users/:id", handler: usersHandler);
// it is also possible to define the route transition to use
// router.define("users/:id", handler: usersHandler, transitionType: TransitionType.inFromLeft);
}
```
@ -83,12 +78,13 @@ for you.
You can also manually push to a route yourself. To do so:
```dart
router.navigateTo(context, "/users/1234", transition: TransitionType.fadeIn);
router.navigateTo(context, "/users/1234",
transition: TransitionType.fadeIn);
```
<hr/>
Fluro is a Yakka original.
<br/>
<a href="https://theyakka.com" target="_yakka">
<img src="https://storage.googleapis.com/yakka-logos/logo_wordmark.png"
<hr/>
Fluro is a Posse Production.
<br/>
<a href="http://goposse.com" target="_posse">
<img src="https://storage.googleapis.com/posse-logos/logo-posse.png"
width="60"></a>

View File

@ -1,18 +1,19 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "../config.gradle"
apply from: "../flutter.gradle"
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
compileSdkVersion versions.targetSDK
buildToolsVersion "${versions.buildTools}"
defaultConfig {
minSdkVersion 24
targetSdkVersion 29
applicationId "app.yakka.fluroexample"
versionCode 1
versionName "1.6.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
minSdkVersion versions.minSDK
targetSdkVersion versions.targetSDK
applicationId "$appInfo.applicationID"
versionCode appInfo.build
versionName "${appInfo.version}"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
@ -27,15 +28,15 @@ android {
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
compile fileTree(dir: 'libs', include: ['*.jar'])
// kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61"
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
// google
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
compile "com.android.support:appcompat-v7:${versions.googleSupport}"
compile "com.android.support:support-v13:${versions.googleSupport}"
compile "com.android.support:support-v4:${versions.googleSupport}"
// testing
androidTestImplementation 'androidx.annotation:annotation:1.1.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:rules:1.2.0'
androidTestCompile "com.android.support:support-annotations:${versions.googleSupport}"
androidTestCompile 'com.android.support.test:runner:1.0.1'
androidTestCompile 'com.android.support.test:rules:1.0.1'
}

View File

@ -9,7 +9,7 @@ import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterActivity() {
private val logTag = "A:Main"
private val LOG_TAG = "A:Main"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -17,13 +17,16 @@ class MainActivity : FlutterActivity() {
checkForLinkEvent(intent)
}
override fun onResume() {
super.onResume()
}
private fun checkForLinkEvent(intent: Intent) {
val data = intent.data
if (intent.action == Intent.ACTION_VIEW && data != null) {
val path = data.getQueryParameter("path")
val text = data.getQueryParameter("message") ?: "Why you don't enter text?"
if (intent.action == Intent.ACTION_VIEW && intent.data != null) {
val path = intent.data.getQueryParameter("path")
val text = intent.data.getQueryParameter("message") ?: "Why you don't enter text?"
if (path != null) {
Log.d(logTag, "Setting initial route to: $path?message=$text")
Log.d(LOG_TAG, "Setting initial route to: $path?message=$text")
flutterView.setInitialRoute("$path?message=$text")
}
}

View File

@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.3.61'
ext.kotlin_version = '1.2.30'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.android.tools.build:gradle:3.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

View File

@ -1,13 +1,13 @@
ext.appInfo = [
version: '1.6.0',
version: '1.3.0',
build: 1,
applicationID: "com.goposse.fluro"
]
ext.versions = [
minSDK: 21,
targetSDK: 29,
buildTools: '29.0.3',
kotlin: '1.3.61',
targetSDK: 27,
buildTools: '27.0.3',
kotlin: '1.2.30',
googleSupport: '27.1.0'
]

View File

@ -1,4 +1 @@
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
android.useAndroidX=true
android.enableJetifier=true

View File

@ -1,93 +0,0 @@
Copyright 2015 SUNRISE DIGITAL, Juan Hodgson Authors (srdigital@msn.com)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 882 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,18 +0,0 @@
#
# NOTE: This podspec is NOT to be published. It is only used as a local source!
#
Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '1.0.0'
s.summary = 'High-performance, high-fidelity mobile apps.'
s.description = <<-DESC
Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS.
DESC
s.homepage = 'https://flutter.io'
s.license = { :type => 'MIT' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
s.vendored_frameworks = 'Flutter.framework'
end

View File

@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
41FA87031F2620DA005CDA4D /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 41FA87021F2620DA005CDA4D /* GeneratedPluginRegistrant.m */; };
@ -39,6 +40,7 @@
/* Begin PBXFileReference section */
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
41FA87011F2620DA005CDA4D /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
41FA87021F2620DA005CDA4D /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
@ -74,6 +76,7 @@
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
@ -187,6 +190,7 @@
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,

View File

@ -7,11 +7,8 @@
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface GeneratedPluginRegistrant : NSObject
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry;
@end
NS_ASSUME_NONNULL_END
#endif /* GeneratedPluginRegistrant_h */

View File

@ -1,43 +1,43 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import 'package:fluro/fluro.dart';
import 'package:router_example/config/application.dart';
import 'package:flutter/material.dart';
import '../../config/application.dart';
import '../../config/routes.dart';
import 'package:fluro/fluro.dart';
import 'package:router_example/config/routes.dart';
class AppComponent extends StatefulWidget {
@override
State createState() {
return AppComponentState();
return new AppComponentState();
}
}
class AppComponentState extends State<AppComponent> {
AppComponentState() {
final router = Router();
final router = new Router();
Routes.configureRoutes(router);
Application.router = router;
}
@override
Widget build(BuildContext context) {
final app = MaterialApp(
final app = new MaterialApp(
title: 'Fluro',
debugShowCheckedModeBanner: false,
theme: ThemeData(
theme: new ThemeData(
primarySwatch: Colors.blue,
),
onGenerateRoute: Application.router.generator,
navigatorKey: Application.routerKey,
);
// print("initial route = ${app.initialRoute}");
print("initial route = ${app.initialRoute}");
return app;
}
}

View File

@ -1,32 +1,32 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class DemoMessageComponent extends StatelessWidget {
DemoMessageComponent(
{@required this.message, this.color = const Color(0xFFFFFFFF)});
DemoMessageComponent({@required this.message, this.color = const Color(0xFFFFFFFF)});
final String message;
final Color color;
@override
Widget build(BuildContext context) {
return Material(
return new Material(
color: this.color,
child: Center(
child: Text(
child: new Center(
child: new Text(
message,
style: TextStyle(
style: new TextStyle(
fontFamily: "Lazer84",
),
),
)
),
);
}
}
}

View File

@ -1,21 +1,22 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import 'package:flutter/material.dart';
class DemoResultComponent extends StatefulWidget {
@override
_DemoResultComponentState createState() => _DemoResultComponentState();
_DemoResultComponentState createState() => new _DemoResultComponentState();
}
class _DemoResultComponentState extends State<DemoResultComponent> {
@override
Widget build(BuildContext context) {
return Container();
return new Container(
);
}
}
}

View File

@ -1,19 +1,16 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import '../../helpers/color_helpers.dart';
import 'package:router_example/helpers/color_helpers.dart';
import 'package:flutter/material.dart';
class DemoSimpleComponent extends StatelessWidget {
DemoSimpleComponent(
{String message = "Testing",
Color color = const Color(0xFFFFFFFF),
String result})
DemoSimpleComponent({String message = "Testing", Color color = const Color(0xFFFFFFFF), String result})
: this.message = message,
this.color = color,
this.result = result;
@ -24,36 +21,34 @@ class DemoSimpleComponent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Material(
return new Material(
color: color,
child: Column(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image(
image: AssetImage("assets/images/acc_boom.png"),
new Image(
image: new AssetImage("assets/images/acc_boom.png"),
color: ColorHelpers.blackOrWhiteContrastColor(color),
width: 260.0,
),
Padding(
padding: EdgeInsets.only(left: 50.0, right: 50.0, top: 15.0),
child: Text(
new Padding(
padding: new EdgeInsets.only(left: 50.0, right: 50.0, top: 15.0),
child: new Text(
message,
textAlign: TextAlign.center,
style: TextStyle(
style: new TextStyle(
color: ColorHelpers.blackOrWhiteContrastColor(color),
height: 2.0,
),
),
),
Padding(
padding: EdgeInsets.only(top: 15.0),
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: 42.0),
child: FlatButton(
highlightColor:
ColorHelpers.blackOrWhiteContrastColor(color).withAlpha(17),
splashColor:
ColorHelpers.blackOrWhiteContrastColor(color).withAlpha(34),
new Padding(
padding: new EdgeInsets.only(top: 15.0),
child: new ConstrainedBox(
constraints: new BoxConstraints(minHeight: 42.0),
child: new FlatButton(
highlightColor: ColorHelpers.blackOrWhiteContrastColor(color).withAlpha(17),
splashColor: ColorHelpers.blackOrWhiteContrastColor(color).withAlpha(34),
onPressed: () {
if (result == null) {
Navigator.pop(context);
@ -61,9 +56,9 @@ class DemoSimpleComponent extends StatelessWidget {
Navigator.pop(context, result);
}
},
child: Text(
child: new Text(
"OK",
style: TextStyle(
style: new TextStyle(
fontSize: 18.0,
color: ColorHelpers.blackOrWhiteContrastColor(color),
),
@ -75,4 +70,4 @@ class DemoSimpleComponent extends StatelessWidget {
),
);
}
}
}

View File

@ -1,50 +1,42 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import 'dart:async';
import 'package:router_example/config/application.dart';
import 'package:fluro/fluro.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../config/application.dart';
class HomeComponent extends StatefulWidget {
@override
State createState() => HomeComponentState();
State createState() => new HomeComponentState();
}
class HomeComponentState extends State<HomeComponent> {
var _deepLinkOpacity = 1.0;
final _deepLinkURL =
"fluro://deeplink?path=/message&mesage=fluro%20rocks%21%21";
final _deepLinkURL = "fluro://deeplink?path=/message&mesage=fluro%20rocks%21%21";
final _daysOfWeek = const [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
];
Widget deepLinkWidget(BuildContext context) {
return Stack(
return new Stack(
children: <Widget>[
// copied widget
AnimatedOpacity(
new AnimatedOpacity(
opacity: (_deepLinkOpacity - 1.0).abs(),
duration: Duration(milliseconds: 400),
child: Center(
child: Text(
duration: new Duration(milliseconds: 400),
child: new Center(
child: new Text(
"Copied to clipboard!",
style: TextStyle(
style: new TextStyle(
fontSize: 14.0,
color: const Color(0xFFFFFFFF),
fontWeight: FontWeight.w500,
@ -53,16 +45,16 @@ class HomeComponentState extends State<HomeComponent> {
),
),
// button widget
AnimatedOpacity(
new AnimatedOpacity(
opacity: _deepLinkOpacity,
duration: Duration(milliseconds: 250),
child: Center(
child: FlatButton(
duration: new Duration(milliseconds: 250),
child: new Center(
child: new FlatButton(
highlightColor: const Color(0x11FFFFFF),
splashColor: const Color(0x22FFFFFF),
onPressed: () {
if (_deepLinkOpacity == 1.0) {
Timer(Duration(milliseconds: 2000), () {
new Timer(new Duration(milliseconds: 2000), () {
setState(() {
_deepLinkOpacity = 1.0;
});
@ -70,16 +62,16 @@ class HomeComponentState extends State<HomeComponent> {
setState(() {
_deepLinkOpacity = 0.0;
});
final clipboardData = ClipboardData(text: _deepLinkURL);
final clipboardData = new ClipboardData(text: _deepLinkURL);
Clipboard.setData(clipboardData);
}
},
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
child: new Padding(
padding: new EdgeInsets.all(8.0),
child: new Text(
"Click here to copy a deep link url to the clipboard",
textAlign: TextAlign.center,
style: TextStyle(
style: new TextStyle(
fontSize: 12.0,
color: const Color(0xCCFFFFFF),
),
@ -95,99 +87,50 @@ class HomeComponentState extends State<HomeComponent> {
@override
Widget build(BuildContext context) {
var menuWidgets = <Widget>[
menuButton(context, 'assets/images/ic_transform_native_hz.png',
"Native Animation", "native"),
menuButton(context, 'assets/images/ic_transform_fade_in_hz.png',
"Preset (Fade In)", "preset-fade"),
menuButton(context, 'assets/images/ic_transform_global_hz.png',
"Preset (Global transition)", "fixed-trans"),
menuButton(context, 'assets/images/ic_transform_custom_hz.png',
"Custom Transition", "custom"),
menuButton(context, 'assets/images/ic_result_hz.png', "Navigator Result",
"pop-result"),
menuButton(context, 'assets/images/ic_function_hz.png', "Function Call",
"function-call"),
new Padding(
padding: new EdgeInsets.only(bottom: 35.0),
child: new Image(image: new AssetImage("assets/images/logo_fluro.png"), width: 200.0),
),
menuButton(context, "Native Animation", "native"),
menuButton(context, "Preset (In from Left)", "preset-from-left"),
menuButton(context, "Preset (Fade In)", "preset-fade"),
menuButton(context, "Custom Transition", "custom"),
menuButton(context, "Navigator Result", "pop-result"),
menuButton(context, "Function Call", "function-call"),
new Padding(
padding: new EdgeInsets.only(top: 65.0, left: 60.0, right: 60.0),
child: new Center(
child: new ConstrainedBox(
constraints: new BoxConstraints.tightFor(height: 60.0),
child: deepLinkWidget(context),
),
),
),
];
final size = MediaQuery.of(context).size;
final childRatio = (size.width / size.height) * 2.5;
return Material(
return new Material(
color: const Color(0xFF00D6F7),
child: SafeArea(
top: true,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 25, bottom: 35, left: 25),
child: Image(
image: AssetImage("assets/images/logo_fluro.png"),
width: 100.0,
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: GridView.count(
childAspectRatio: childRatio,
crossAxisCount: 2,
mainAxisSpacing: 5,
children: menuWidgets,
),
),
),
// Padding(
// padding: EdgeInsets.only(top: 35.0, bottom: 25),
// child: Center(
// child: ConstrainedBox(
// constraints: BoxConstraints.tightFor(height: 60.0),
// child: deepLinkWidget(context),
// ),
// ),
// ),
],
),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: menuWidgets,
),
);
}
// helpers
Widget menuButton(
BuildContext context, String assetSrc, String title, String key) {
return Padding(
padding: EdgeInsets.all(4.0),
child: Container(
height: 42.0,
child: FlatButton(
color: const Color(0x22FFFFFF),
Widget menuButton(BuildContext context, String title, String key) {
return new Padding(
padding: new EdgeInsets.all(4.0),
child: new ConstrainedBox(
constraints: new BoxConstraints(minHeight: 42.0),
child: new FlatButton(
highlightColor: const Color(0x11FFFFFF),
splashColor: const Color(0x22FFFFFF),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Container(
height: 36,
child: Image.asset(
assetSrc,
fit: BoxFit.contain,
),
),
),
Text(
title,
textAlign: TextAlign.center,
style: TextStyle(
color: const Color(0xAA001133),
),
)
],
child: new Text(
title,
style: new TextStyle(
color: const Color(0xAA001133),
),
),
onPressed: () {
tappedMenuButton(context, key);
@ -202,27 +145,24 @@ class HomeComponentState extends State<HomeComponent> {
String message = "";
String hexCode = "#FFFFFF";
String result;
TransitionType transitionType = TransitionType.native;
if (key != "custom" && key != "function-call" && key != "fixed-trans") {
TransitionType transitionType = TransitionType.fluroNative;
if (key != "custom" && key != "function-call") {
if (key == "native") {
hexCode = "#F76F00";
message =
"This screen should have appeared using the default flutter animation for the current OS";
message = "This screen should have appeared using the default flutter animation for the current OS";
} else if (key == "preset-from-left") {
hexCode = "#5BF700";
message =
"This screen should have appeared with a slide in from left transition";
message = "This screen should have appeared with a slide in from left transition";
transitionType = TransitionType.inFromLeft;
} else if (key == "preset-fade") {
hexCode = "#F700D2";
message = "This screen should have appeared with a fade in transition";
transitionType = TransitionType.fadeIn;
} else if (key == "pop-result") {
transitionType = TransitionType.native;
transitionType = TransitionType.fluroNative;
hexCode = "#7d41f4";
message =
"When you close this screen you should see the current day of the week";
result = "Today is ${_daysOfWeek[DateTime.now().weekday - 1]}!";
message = "When you close this screen you should see the current day of the week";
result = "Today is ${_daysOfWeek[new DateTime.now().weekday]}!";
}
String route = "/demo?message=$message&color_hex=$hexCode";
@ -231,40 +171,37 @@ class HomeComponentState extends State<HomeComponent> {
route = "$route&result=$result";
}
Application.router
.navigateTo(Application.routerKey, route, transition: transitionType)
.then((result) {
if (key == "pop-result") {
Application.router.navigateTo(Application.routerKey, "/demo/func?message=$result");
}
});
Application.router.navigateTo(
context, route,
transition: transitionType).then((result) {
if (key == "pop-result") {
Application.router.navigateTo(context, "/demo/func?message=$result");
}
});
} else if (key == "custom") {
hexCode = "#DFF700";
message =
"This screen should have appeared with a crazy custom transition";
var transition = (BuildContext context, Animation<double> animation,
message = "This screen should have appeared with a crazy custom transition";
var transition =
(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
return ScaleTransition(
return new ScaleTransition(
scale: animation,
child: RotationTransition(
child: new RotationTransition(
turns: animation,
child: child,
),
);
};
Application.router.navigateTo(
Application.routerKey,
context,
"/demo?message=$message&color_hex=$hexCode",
transition: TransitionType.custom,
transitionBuilder: transition,
transitionDuration: const Duration(milliseconds: 600),
);
} else if (key == "fixed-trans") {
Application.router.navigateTo(
Application.routerKey, "/demo/fixedtrans?message=Hello!&color_hex=#f4424b");
} else {
message = "You tapped the function button!";
Application.router.navigateTo(Application.routerKey, "/demo/func?message=$message");
Application.router.navigateTo(context, "/demo/func?message=$message");
}
}
}

View File

@ -1,16 +1,12 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
class Application {
static Router router;
static GlobalKey<NavigatorState> routerKey = GlobalKey<NavigatorState>();
}
}

View File

@ -1,60 +1,57 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import '../helpers/color_helpers.dart';
import '../components/demo/demo_simple_component.dart';
import '../components/home/home_component.dart';
import 'package:router_example/helpers/color_helpers.dart';
import 'package:router_example/components/demo/demo_simple_component.dart';
import 'package:router_example/components/home/home_component.dart';
import 'package:flutter/painting.dart';
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
var rootHandler = Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return HomeComponent();
var rootHandler = new Handler(handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return new HomeComponent();
});
var demoRouteHandler = Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
var demoRouteHandler = new Handler(handlerFunc: (BuildContext context, Map<String, List<String>> params) {
String message = params["message"]?.first;
String colorHex = params["color_hex"]?.first;
String result = params["result"]?.first;
Color color = Color(0xFFFFFFFF);
Color color = new Color(0xFFFFFFFF);
if (colorHex != null && colorHex.length > 0) {
color = Color(ColorHelpers.fromHexString(colorHex));
color = new Color(ColorHelpers.fromHexString(colorHex));
}
return DemoSimpleComponent(message: message, color: color, result: result);
return new DemoSimpleComponent(message: message, color: color, result: result);
});
var demoFunctionHandler = Handler(
var demoFunctionHandler = new Handler(
type: HandlerType.function,
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
String message = params["message"]?.first;
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(
return new AlertDialog(
title: new Text(
"Hey Hey!",
style: TextStyle(
style: new TextStyle(
color: const Color(0xFF00D6F7),
fontFamily: "Lazer84",
fontSize: 22.0,
),
),
content: Text("$message"),
content: new Text("$message"),
actions: <Widget>[
Padding(
padding: EdgeInsets.only(bottom: 8.0, right: 8.0),
child: FlatButton(
new Padding(
padding: new EdgeInsets.only(bottom: 8.0, right: 8.0),
child: new FlatButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text("OK"),
child: new Text("OK"),
),
),
],
@ -65,16 +62,15 @@ var demoFunctionHandler = Handler(
/// Handles deep links into the app
/// To test on Android:
///
/// `adb shell am start -W -a android.intent.action.VIEW -d "fluro://deeplink?path=/message&mesage=fluro%20rocks%21%21" com.theyakka.fluro`
var deepLinkHandler = Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
///
/// `adb shell am start -W -a android.intent.action.VIEW -d "fluro://deeplink?path=/message&mesage=fluro%20rocks%21%21" com.goposse.fluro`
var deepLinkHandler = new Handler(handlerFunc: (BuildContext context, Map<String, List<String>> params) {
String message = params["message"]?.first;
String colorHex = params["color_hex"]?.first;
String result = params["result"]?.first;
Color color = Color(0xFFFFFFFF);
Color color = new Color(0xFFFFFFFF);
if (colorHex != null && colorHex.length > 0) {
color = Color(ColorHelpers.fromHexString(colorHex));
color = new Color(ColorHelpers.fromHexString(colorHex));
}
return DemoSimpleComponent(
message: "DEEEEEP LINK!!!", color: color, result: result);
return new DemoSimpleComponent(message: message, color: color, result: result);
});

View File

@ -1,32 +1,29 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import './route_handlers.dart';
import 'package:router_example/config/route_handlers.dart';
class Routes {
static String root = "/";
static String demoSimple = "/demo";
static String demoSimpleFixedTrans = "/demo/fixedtrans";
static String demoFunc = "/demo/func";
static String deepLink = "/message";
static void configureRoutes(Router router) {
router.notFoundHandler = Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
router.notFoundHandler = new Handler(handlerFunc: (BuildContext context, Map<String, List<String>> params) {
print("ROUTE WAS NOT FOUND !!!");
});
router.define(root, handler: rootHandler);
router.define(demoSimple, handler: demoRouteHandler);
router.define(demoSimpleFixedTrans,
handler: demoRouteHandler, transitionType: TransitionType.inFromLeft);
router.define(demoFunc, handler: demoFunctionHandler);
router.define(deepLink, handler: deepLinkHandler);
}
}
}

View File

@ -1,9 +1,8 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import 'package:flutter/material.dart';
@ -15,6 +14,7 @@ enum ContrastPreference {
}
class ColorHelpers {
static int fromHexString(String argbHexString) {
String useString = argbHexString;
if (useString.startsWith("#")) {
@ -36,22 +36,16 @@ class ColorHelpers {
/// or lighter. If darker, will return white. If lighter, will return
/// black. If the color is within 35-65% of the spectrum and a prefer
/// value is specified, then white or black will be preferred.
static Color blackOrWhiteContrastColor(Color sourceColor,
{ContrastPreference prefer = ContrastPreference.none}) {
static Color blackOrWhiteContrastColor(Color sourceColor, {ContrastPreference prefer = ContrastPreference.none}) {
// Will return a value between 0.0 (black) and 1.0 (white)
double value = (((sourceColor.red * 299.0) +
(sourceColor.green * 587.0) +
(sourceColor.blue * 114.0)) /
1000.0) /
255.0;
double value = (((sourceColor.red * 299.0) + (sourceColor.green * 587.0) +
(sourceColor.blue * 114.0)) / 1000.0) / 255.0;
if (prefer != ContrastPreference.none) {
if (value >= _kMinContrastModifierRange &&
value <= _kMaxContrastModifierRange) {
return prefer == ContrastPreference.light
? Color(0xFFFFFFFF)
: Color(0xFF000000);
if (value >= _kMinContrastModifierRange && value <= _kMaxContrastModifierRange) {
return prefer == ContrastPreference.light ? new Color(0xFFFFFFFF) : new Color(0xFF000000);
}
}
return value > 0.6 ? Color(0xFF000000) : Color(0xFFFFFFFF);
return value > 0.6 ? new Color(0xFF000000) : new Color(0xFFFFFFFF);
}
}
}

View File

@ -1,14 +1,13 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import 'components/app/app_component.dart';
import 'package:flutter/material.dart';
void main() {
runApp(AppComponent());
}
runApp(new AppComponent());
}

View File

@ -11,13 +11,6 @@ flutter:
assets:
- assets/images/logo_fluro.png
- assets/images/acc_boom.png
- assets/images/ic_result_hz.png
- assets/images/ic_function_hz.png
- assets/images/ic_transform_custom_hz.png
- assets/images/ic_transform_fade_in_hz.png
- assets/images/ic_transform_fade_out_hz.png
- assets/images/ic_transform_global_hz.png
- assets/images/ic_transform_native_hz.png
fonts:
- family: Lazer84
fonts:

View File

@ -1,13 +1,19 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
library fluro;
export 'src/common.dart';
export 'src/router.dart';
export 'src/tree.dart';
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
part 'src/common.dart';
part 'src/routable.dart';
part 'src/router.dart';
part 'src/tree.dart';

View File

@ -1,13 +1,11 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import 'package:flutter/widgets.dart';
part of fluro;
///
enum HandlerType {
@ -17,7 +15,7 @@ enum HandlerType {
///
class Handler {
const Handler({this.type = HandlerType.route, this.handlerFunc});
Handler({this.type = HandlerType.route, this.handlerFunc});
final HandlerType type;
final HandlerFunc handlerFunc;
}
@ -34,22 +32,7 @@ typedef Widget HandlerFunc(
class AppRoute {
String route;
dynamic handler;
TransitionType transitionType;
AppRoute(this.route, this.handler, {this.transitionType});
}
enum TransitionType {
native,
nativeModal,
inFromLeft,
inFromRight,
inFromBottom,
fadeIn,
custom, // if using custom then you must also provide a transition
material,
materialFullScreenDialog,
cupertino,
cupertinoFullScreenDialog,
AppRoute(this.route, this.handler);
}
enum RouteMatchType {
@ -69,13 +52,9 @@ class RouteMatch {
final String errorMessage;
}
class RouteNotFoundException implements Exception {
final String message;
final String path;
RouteNotFoundException(this.message, this.path);
@override
String toString() {
return "No registered route was found to handle '$path'";
}
TargetPlatform currentPlatform() {
if (Platform.isIOS) return TargetPlatform.iOS;
if (Platform.isAndroid) return TargetPlatform.android;
if (Platform.isFuchsia) return TargetPlatform.fuchsia;
throw Exception("Unsupported platform");
}

84
lib/src/routable.dart Normal file
View File

@ -0,0 +1,84 @@
/*
* fluro
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
part of fluro;
abstract class Routable {
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {}
void didAppear(
bool wasPushed,
Route<dynamic> route,
Route<dynamic> previousRoute,
) {}
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {}
}
typedef String ScreenNameExtractor(RouteSettings settings);
String defaultNameExtractor(RouteSettings settings) => settings.name;
class RoutableObserver extends RouteObserver<PageRoute<dynamic>> {
final ScreenNameExtractor nameExtractor = defaultNameExtractor;
@override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
super.didPush(route, previousRoute);
if (route is PageRoute) {
final routeWidget = route.buildPage(
route.navigator.context, route.animation, route.secondaryAnimation);
if (routeWidget is Routable) {
Routable w = (routeWidget as Routable);
w.didPush(route, previousRoute);
w.didAppear(true, route, previousRoute);
}
}
}
@override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
super.didPop(route, previousRoute);
if (route is PageRoute) {
final leavingWidget = route.buildPage(
route.navigator.context, route.animation, route.secondaryAnimation);
if (leavingWidget is Routable) {
Routable w = (leavingWidget as Routable);
w.didPop(route, previousRoute);
}
}
if (previousRoute is PageRoute) {
final returningWidget = previousRoute.buildPage(
previousRoute.navigator.context,
previousRoute.animation,
previousRoute.secondaryAnimation);
if (returningWidget is Routable) {
Routable w = (returningWidget as Routable);
w.didAppear(false, route, previousRoute);
}
}
}
@override
void didReplace({Route newRoute, Route oldRoute}) {
super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
if (oldRoute is PageRoute) {
final leavingWidget = oldRoute.buildPage(oldRoute.navigator.context,
oldRoute.animation, oldRoute.secondaryAnimation);
if (leavingWidget is Routable) {
Routable w = (leavingWidget as Routable);
w.didPop(oldRoute, newRoute);
}
}
if (newRoute is PageRoute) {
final returningWidget = newRoute.buildPage(newRoute.navigator.context,
newRoute.animation, newRoute.secondaryAnimation);
if (returningWidget is Routable) {
Routable w = (returningWidget as Routable);
w.didAppear(false, newRoute, oldRoute);
}
}
}
}

View File

@ -1,35 +1,36 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
part of fluro;
import 'dart:async';
import 'package:fluro/fluro.dart';
import 'package:fluro/src/common.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
enum TransitionType {
native,
nativeModal,
fluroNative,
inFromLeft,
inFromRight,
inFromBottom,
fadeIn,
custom, // if using custom then you must also provide a transition
}
class Router {
static final appRouter = Router();
static final appRouter = new Router();
/// The tree structure that stores the defined routes
final RouteTree _routeTree = RouteTree();
final RouteTree _routeTree = new RouteTree();
/// Generic handler for when a route has not been defined
Handler notFoundHandler;
/// Creates a [PageRoute] definition for the passed [RouteHandler]. You can optionally provide a default transition type.
void define(String routePath,
{@required Handler handler, TransitionType transitionType}) {
_routeTree.addRoute(
AppRoute(routePath, handler, transitionType: transitionType),
);
/// Creates a [PageRoute] definition for the passed [RouteHandler]. You can optionally provide a custom
/// transition builder for the route.
void define(String routePath, {@required Handler handler}) {
_routeTree.addRoute(new AppRoute(routePath, handler));
}
/// Finds a defined [AppRoute] for the path value. If no [AppRoute] definition was found
@ -38,59 +39,59 @@ class Router {
return _routeTree.matchRoute(path);
}
void pop(GlobalKey<NavigatorState> key) => key.currentState.pop();
///
Future navigateTo(GlobalKey<NavigatorState> key, String path,
Future navigateTo(BuildContext context, String path,
{bool replace = false,
bool clearStack = false,
TransitionType transition,
TransitionType transition = TransitionType.fluroNative,
Duration transitionDuration = const Duration(milliseconds: 250),
RouteTransitionsBuilder transitionBuilder}) {
RouteMatch routeMatch = matchRoute(key.currentContext, path,
RouteMatch routeMatch = matchRoute(context, path,
transitionType: transition,
transitionsBuilder: transitionBuilder,
transitionDuration: transitionDuration);
Route<dynamic> route = routeMatch.route;
Completer completer = Completer();
Completer completer = new Completer();
Future future = completer.future;
if (routeMatch.matchType == RouteMatchType.nonVisual) {
completer.complete("Non visual route type.");
} else {
if (route == null && notFoundHandler != null) {
route = _notFoundRoute(path);
route = _notFoundRoute(context, path);
}
if (route != null) {
if (clearStack) {
future =
key.currentState.pushAndRemoveUntil(route, (check) => false);
} else {
future = replace
? key.currentState.pushReplacement(route)
: key.currentState.push(route);
}
future = replace
? Navigator.pushReplacement(context, route)
: Navigator.push(context, route);
completer.complete();
} else {
String error = "No registered route was found to handle '$path'.";
print(error);
completer.completeError(RouteNotFoundException(error, path));
completer.completeError(error);
}
}
return future;
}
bool pop(BuildContext context) => Navigator.of(context).pop();
List<NavigatorObserver> get routerObservers {
return [
new RoutableObserver(),
];
}
///
Route<Null> _notFoundRoute(String path) {
Route<Null> _notFoundRoute(BuildContext context, String path) {
RouteCreator<Null> creator =
(RouteSettings routeSettings, Map<String, List<String>> parameters) {
return MaterialPageRoute<Null>(
return new MaterialPageRoute<Null>(
settings: routeSettings,
builder: (BuildContext context) {
return notFoundHandler.handlerFunc(context, parameters);
});
};
return creator(RouteSettings(name: path), null);
return creator(new RouteSettings(name: path), null);
}
///
@ -101,17 +102,13 @@ class Router {
RouteTransitionsBuilder transitionsBuilder}) {
RouteSettings settingsToUse = routeSettings;
if (routeSettings == null) {
settingsToUse = RouteSettings(name: path);
settingsToUse = new RouteSettings(name: path);
}
AppRouteMatch match = _routeTree.matchRoute(path);
AppRoute route = match?.route;
Handler handler = (route != null ? route.handler : notFoundHandler);
var transition = transitionType;
if (transitionType == null) {
transition = route != null ? route.transitionType : TransitionType.native;
}
if (route == null && notFoundHandler == null) {
return RouteMatch(
return new RouteMatch(
matchType: RouteMatchType.noMatch,
errorMessage: "No matching route was found");
}
@ -119,55 +116,36 @@ class Router {
match?.parameters ?? <String, List<String>>{};
if (handler.type == HandlerType.function) {
handler.handlerFunc(buildContext, parameters);
return RouteMatch(matchType: RouteMatchType.nonVisual);
return new RouteMatch(matchType: RouteMatchType.nonVisual);
}
final platform = currentPlatform();
RouteCreator creator =
(RouteSettings routeSettings, Map<String, List<String>> parameters) {
bool isNativeTransition = (transition == TransitionType.native ||
transition == TransitionType.nativeModal);
// We use the standard material route for .native, .nativeModal and
// .fluroNative if you're on iOS
bool isNativeTransition = (transitionType == TransitionType.native ||
transitionType == TransitionType.nativeModal ||
(transitionType == TransitionType.fluroNative &&
platform != TargetPlatform.android));
if (isNativeTransition) {
if (Theme.of(buildContext).platform == TargetPlatform.iOS) {
return CupertinoPageRoute<dynamic>(
settings: routeSettings,
fullscreenDialog: transition == TransitionType.nativeModal,
builder: (BuildContext context) {
return handler.handlerFunc(context, parameters);
});
} else {
return MaterialPageRoute<dynamic>(
settings: routeSettings,
fullscreenDialog: transition == TransitionType.nativeModal,
builder: (BuildContext context) {
return handler.handlerFunc(context, parameters);
});
}
} else if (transition == TransitionType.material ||
transition == TransitionType.materialFullScreenDialog) {
return MaterialPageRoute<dynamic>(
return new MaterialPageRoute<dynamic>(
settings: routeSettings,
fullscreenDialog:
transition == TransitionType.materialFullScreenDialog,
builder: (BuildContext context) {
return handler.handlerFunc(context, parameters);
});
} else if (transition == TransitionType.cupertino ||
transition == TransitionType.cupertinoFullScreenDialog) {
return CupertinoPageRoute<dynamic>(
settings: routeSettings,
fullscreenDialog:
transition == TransitionType.cupertinoFullScreenDialog,
builder: (BuildContext context) {
return handler.handlerFunc(context, parameters);
});
fullscreenDialog: transitionType == TransitionType.nativeModal,
builder: (BuildContext context) =>
handler.handlerFunc(context, parameters));
} else {
var routeTransitionsBuilder;
if (transition == TransitionType.custom) {
if (transitionType == TransitionType.custom) {
routeTransitionsBuilder = transitionsBuilder;
} else {
routeTransitionsBuilder = _standardTransitionsBuilder(transition);
if (transitionType == TransitionType.fluroNative &&
platform == TargetPlatform.android) {
transitionDuration = new Duration(milliseconds: 150);
}
routeTransitionsBuilder = _standardTransitionsBuilder(transitionType);
}
return PageRouteBuilder<dynamic>(
return new PageRouteBuilder<dynamic>(
settings: routeSettings,
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
@ -178,7 +156,7 @@ class Router {
);
}
};
return RouteMatch(
return new RouteMatch(
matchType: RouteMatchType.visual,
route: creator(settingsToUse, parameters),
);
@ -188,8 +166,26 @@ class Router {
TransitionType transitionType) {
return (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
if (transitionType == TransitionType.fadeIn) {
return FadeTransition(opacity: animation, child: child);
if (transitionType == TransitionType.fluroNative) {
return new SlideTransition(
position: new Tween<Offset>(
begin: const Offset(0.0, 0.12),
end: const Offset(0.0, 0.0),
).animate(new CurvedAnimation(
parent: animation,
curve: new Interval(0.125, 0.950, curve: Curves.fastOutSlowIn),
reverseCurve: Curves.easeOut,
)),
child: new FadeTransition(
opacity: new Tween<double>(
begin: 0.0,
end: 1.0,
).animate(animation),
child: child,
),
);
} else if (transitionType == TransitionType.fadeIn) {
return new FadeTransition(opacity: animation, child: child);
} else {
const Offset topLeft = const Offset(0.0, 0.0);
const Offset topRight = const Offset(1.0, 0.0);
@ -204,8 +200,8 @@ class Router {
endOffset = topLeft;
}
return SlideTransition(
position: Tween<Offset>(
return new SlideTransition(
position: new Tween<Offset>(
begin: startOffset,
end: endOffset,
).animate(animation),

View File

@ -1,14 +1,11 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import 'package:fluro/src/common.dart';
import 'package:flutter/widgets.dart';
part of fluro;
enum RouteTreeNodeType {
component,
@ -71,7 +68,7 @@ class RouteTree {
// could be affected
throw ("Default route was already defined");
}
var node = RouteTreeNode(path, RouteTreeNodeType.component);
var node = new RouteTreeNode(path, RouteTreeNodeType.component);
node.routes = [route];
_nodes.add(node);
_hasDefaultRoute = true;
@ -87,7 +84,7 @@ class RouteTree {
RouteTreeNode node = _nodeForComponent(component, parent);
if (node == null) {
RouteTreeNodeType type = _typeForComponent(component);
node = RouteTreeNode(component, type);
node = new RouteTreeNode(component, type);
node.parent = parent;
if (parent == null) {
_nodes.add(node);
@ -135,7 +132,7 @@ class RouteTree {
if (isMatch) {
RouteTreeNodeMatch parentMatch = nodeMatches[node.parent];
RouteTreeNodeMatch match =
RouteTreeNodeMatch.fromMatch(parentMatch, node);
new RouteTreeNodeMatch.fromMatch(parentMatch, node);
if (node.isParameter()) {
String paramKey = node.part.substring(1);
match.parameters[paramKey] = [pathPart];
@ -165,7 +162,7 @@ class RouteTree {
nodeToUse.routes != null &&
nodeToUse.routes.length > 0) {
List<AppRoute> routes = nodeToUse.routes;
AppRouteMatch routeMatch = AppRouteMatch(routes[0]);
AppRouteMatch routeMatch = new AppRouteMatch(routes[0]);
routeMatch.parameters = match.parameters;
return routeMatch;
}
@ -219,8 +216,8 @@ class RouteTree {
}
Map<String, List<String>> parseQueryString(String query) {
var search = RegExp('([^&=]+)=?([^&]*)');
var params = Map<String, List<String>>();
var search = new RegExp('([^&=]+)=?([^&]*)');
var params = new Map<String, List<String>>();
if (query.startsWith('?')) query = query.substring(1);
decode(String s) => Uri.decodeComponent(s.replaceAll('+', ' '));
for (Match match in search.allMatches(query)) {

View File

@ -1,13 +1,11 @@
name: fluro
description: >
Fluro is a Flutter routing library that adds flexible routing options like wildcards, named
parameters and clear route definitions.
version: 1.6.3
homepage: https://github.com/theyakka/fluro
description: The brightest, hippest, coolest router for Flutter.
version: 1.3.1
author: Posse Productions LLC <apps@goposse.com>
homepage: https://github.com/goposse/fluro
environment:
sdk: ">=2.6.0 <3.0.0"
flutter: ">=1.12.0"
sdk: ">=1.23.0 <2.0.0"
dependencies:
flutter:
@ -16,7 +14,6 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
test: ^1.6.0
flutter:
uses-material-design: false

1
scripts/travis_setup.sh Executable file
View File

@ -0,0 +1 @@
git clone https://github.com/flutter/flutter.git -b alpha --depth 1

View File

@ -1,85 +1,62 @@
/*
* fluro
* Created by Yakka
* https://theyakka.com
*
* Copyright (c) 2019 Yakka, LLC. All rights reserved.
* A Posse Production
* http://goposse.com
* Copyright (c) 2018 Posse Productions LLC. All rights reserved.
* See LICENSE for distribution and usage details.
*/
import 'package:flutter_test/flutter_test.dart';
import 'package:fluro/fluro.dart';
void main() {
testWidgets("Router correctly parses named parameters",
(WidgetTester tester) async {
testWidgets("Router correctly parses named parameters", (WidgetTester tester) async {
String path = "/users/1234";
String route = "/users/:id";
Router router = Router();
Router router = new Router();
router.define(route, handler: null);
AppRouteMatch match = router.match(path);
expect(
match?.parameters,
equals(<String, List<String>>{
"id": ["1234"],
}));
expect(match?.parameters, equals(<String, List<String>>{
"id" : ["1234"],
}));
});
testWidgets("Router correctly parses named parameters with query",
(WidgetTester tester) async {
testWidgets("Router correctly parses named parameters with query", (WidgetTester tester) async {
String path = "/users/1234?name=luke";
String route = "/users/:id";
Router router = Router();
Router router = new Router();
router.define(route, handler: null);
AppRouteMatch match = router.match(path);
expect(
match?.parameters,
equals(<String, List<String>>{
"id": ["1234"],
"name": ["luke"],
}));
expect(match?.parameters, equals(<String, List<String>>{
"id" : ["1234"],
"name" : ["luke"],
}));
});
testWidgets("Router correctly parses query parameters",
(WidgetTester tester) async {
testWidgets("Router correctly parses query parameters", (WidgetTester tester) async {
String path = "/users/create?name=luke&phrase=hello%20world&number=7";
String route = "/users/create";
Router router = Router();
Router router = new Router();
router.define(route, handler: null);
AppRouteMatch match = router.match(path);
expect(
match?.parameters,
equals(<String, List<String>>{
"name": ["luke"],
"phrase": ["hello world"],
"number": ["7"],
}));
expect(match?.parameters, equals(<String, List<String>>{
"name" : ["luke"],
"phrase" : ["hello world"],
"number" : ["7"],
}));
});
testWidgets("Router correctly parses array parameters",
(WidgetTester tester) async {
String path =
"/users/create?name=luke&phrase=hello%20world&number=7&number=10&number=13";
testWidgets("Router correctly parses array parameters", (WidgetTester tester) async {
String path = "/users/create?name=luke&phrase=hello%20world&number=7&number=10&number=13";
String route = "/users/create";
Router router = Router();
Router router = new Router();
router.define(route, handler: null);
AppRouteMatch match = router.match(path);
expect(
match?.parameters,
equals(<String, List<String>>{
"name": ["luke"],
"phrase": ["hello world"],
"number": ["7", "10", "13"],
}));
expect(match?.parameters, equals(<String, List<String>>{
"name" : ["luke"],
"phrase" : ["hello world"],
"number" : ["7", "10", "13"],
}));
});
testWidgets("Router correctly matches route and transition type",
(WidgetTester tester) async {
String path = "/users/1234";
String route = "/users/:id";
Router router = Router();
router.define(route,
handler: null, transitionType: TransitionType.inFromRight);
AppRouteMatch match = router.match(path);
expect(TransitionType.inFromRight, match.route.transitionType);
});
}
}

View File

@ -1,3 +0,0 @@
#!/bin/sh
set -e
$TRAVIS_BUILD_DIR/flutter/bin/flutter test --coverage