Base Flutter App
This commit is contained in:
parent
24c4adf910
commit
f59a5c06ba
5
web_native/.gitignore
vendored
5
web_native/.gitignore
vendored
@ -39,3 +39,8 @@ app.*.symbols
|
||||
|
||||
# Obfuscation related
|
||||
app.*.map.json
|
||||
|
||||
# Android Studio will place build artifacts here
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
|
@ -4,7 +4,7 @@
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: 78910062997c3a836feee883712c241a5fd22983
|
||||
channel: stable
|
||||
revision: b0a22998593fc605c723dee8ff4d9315c32cfe2c
|
||||
channel: beta
|
||||
|
||||
project_type: app
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Imagini
|
||||
# imagini
|
||||
|
||||
A new Flutter project.
|
||||
|
||||
|
@ -26,21 +26,17 @@ apply plugin: 'kotlin-android'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 30
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'InvalidPackage'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "com.reichard.imagini"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 29
|
||||
targetSdkVersion 30
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.web_native">
|
||||
package="com.reichard.imagini">
|
||||
<!-- Flutter needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
|
@ -1,13 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.reichard.Imagini">
|
||||
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
|
||||
calls FlutterMain.startInitialization(this); in its onCreate method.
|
||||
In most cases you can leave this as-is, but you if you want to provide
|
||||
additional functionality it is fine to subclass or reimplement
|
||||
FlutterApplication and put your custom class here. -->
|
||||
package="com.reichard.imagini">
|
||||
<application
|
||||
android:name="io.flutter.app.FlutterApplication"
|
||||
android:label="Imagini"
|
||||
android:label="imagini"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
18
web_native/android/app/src/main/res/values-night/styles.xml
Normal file
18
web_native/android/app/src/main/res/values-night/styles.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
Flutter draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
Flutter draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
@ -12,7 +12,7 @@
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">@android:color/white</item>
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.reichard.Imagini">
|
||||
package="com.reichard.imagini">
|
||||
<!-- Flutter needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
|
@ -6,7 +6,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
|
||||
|
36
web_native/integration_test/app_test.dart
Normal file
36
web_native/integration_test/app_test.dart
Normal file
@ -0,0 +1,36 @@
|
||||
// This is a basic Flutter integration test.
|
||||
//
|
||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||
// utility that Flutter provides. For example, you can send tap and scroll
|
||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'package:imagini/main.dart' as app;
|
||||
|
||||
void main() => run(_testMain);
|
||||
|
||||
void _testMain() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
app.main();
|
||||
|
||||
// Trigger a frame.
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
expect(find.text('1'), findsNothing);
|
||||
|
||||
// Tap the '+' icon and trigger a frame.
|
||||
await tester.tap(find.byIcon(Icons.add));
|
||||
await tester.pump();
|
||||
|
||||
// Verify that our counter has incremented.
|
||||
expect(find.text('0'), findsNothing);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}
|
8
web_native/integration_test/driver.dart
Normal file
8
web_native/integration_test/driver.dart
Normal file
@ -0,0 +1,8 @@
|
||||
// This file is provided as a convenience for running integration tests via the
|
||||
// flutter drive command.
|
||||
//
|
||||
// flutter drive --driver integration_test/driver.dart --target integration_test/app_test.dart
|
||||
|
||||
import 'package:integration_test/integration_test_driver.dart';
|
||||
|
||||
Future<void> main() => integrationDriver();
|
@ -3,7 +3,7 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>App</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
|
@ -1 +1,2 @@
|
||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
@ -1 +1,2 @@
|
||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
41
web_native/ios/Podfile
Normal file
41
web_native/ios/Podfile
Normal file
@ -0,0 +1,41 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '9.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
use_modular_headers!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
end
|
@ -289,17 +289,9 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.webNative;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.reichard.imagini;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@ -421,17 +413,9 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.webNative;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.reichard.imagini;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
@ -448,17 +432,9 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.webNative;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.reichard.imagini;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
@ -11,7 +11,7 @@
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Imagini</string>
|
||||
<string>imagini</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
|
68
web_native/lib/bloc/bloc-prov-tree.dart
Normal file
68
web_native/lib/bloc/bloc-prov-tree.dart
Normal file
@ -0,0 +1,68 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:imagini/bloc/bloc-prov.dart';
|
||||
|
||||
/// A Flutter [Widget] that merges multiple [BlocProvider] widgets into one widget tree.
|
||||
///
|
||||
/// [BlocProviderTree] improves the readability and eliminates the need
|
||||
/// to nest multiple [BlocProviders].
|
||||
///
|
||||
/// By using [BlocProviderTree] we can go from:
|
||||
///
|
||||
/// ```dart
|
||||
/// BlocProvider<BlocA>(
|
||||
/// bloc: BlocA(),
|
||||
/// child: BlocProvider<BlocB>(
|
||||
/// bloc: BlocB(),
|
||||
/// child: BlocProvider<BlocC>(
|
||||
/// value: BlocC(),
|
||||
/// child: ChildA(),
|
||||
/// )
|
||||
/// )
|
||||
/// )
|
||||
/// ```
|
||||
///
|
||||
/// to:
|
||||
///
|
||||
/// ```dart
|
||||
/// BlocProviderTree(
|
||||
/// blocProviders: [
|
||||
/// BlocProvider<BlocA>(bloc: BlocA()),
|
||||
/// BlocProvider<BlocB>(bloc: BlocB()),
|
||||
/// BlocProvider<BlocC>(bloc: BlocC()),
|
||||
/// ],
|
||||
/// child: ChildA(),
|
||||
/// )
|
||||
/// ```
|
||||
///
|
||||
/// [BlocProviderTree] converts the [BlocProvider] list
|
||||
/// into a tree of nested [BlocProvider] widgets.
|
||||
/// As a result, the only advantage of using [BlocProviderTree] is improved
|
||||
/// readability due to the reduction in nesting and boilerplate.
|
||||
class BlocProviderTree extends StatelessWidget {
|
||||
/// The [BlocProvider] list which is converted into a tree of [BlocProvider] widgets.
|
||||
/// The tree of [BlocProvider] widgets is created in order meaning the first [BlocProvider]
|
||||
/// will be the top-most [BlocProvider] and the last [BlocProvider] will be a direct ancestor
|
||||
/// of the `child` [Widget].
|
||||
final List<BlocProvider> blocProviders;
|
||||
|
||||
/// The [Widget] and its descendants which will have access to every [Bloc] provided by `blocProviders`.
|
||||
/// This [Widget] will be a direct descendent of the last [BlocProvider] in `blocProviders`.
|
||||
final Widget child;
|
||||
|
||||
const BlocProviderTree({
|
||||
Key key,
|
||||
@required this.blocProviders,
|
||||
@required this.child,
|
||||
}) : assert(blocProviders != null),
|
||||
assert(child != null),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget tree = child;
|
||||
for (final blocProvider in blocProviders.reversed) {
|
||||
tree = blocProvider.copyWith(tree);
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
}
|
60
web_native/lib/bloc/bloc-prov.dart
Normal file
60
web_native/lib/bloc/bloc-prov.dart
Normal file
@ -0,0 +1,60 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:imagini/bloc/bloc.dart';
|
||||
|
||||
/// A Flutter widget which provides a bloc to its children via `BlocProvider.of(context)`.
|
||||
/// It is used as a DI widget so that a single instance of a bloc can be provided
|
||||
/// to multiple widgets within a subtree.
|
||||
class BlocProvider<T extends Bloc> extends InheritedWidget {
|
||||
/// The [Bloc] which is to be made available throughout the subtree
|
||||
final T bloc;
|
||||
|
||||
/// The [Widget] and its descendants which will have access to the [Bloc].
|
||||
final Widget child;
|
||||
|
||||
BlocProvider({
|
||||
Key key,
|
||||
@required this.bloc,
|
||||
this.child,
|
||||
}) : assert(bloc != null),
|
||||
super(key: key, child: child);
|
||||
|
||||
/// Method that allows widgets to access the bloc as long as their `BuildContext`
|
||||
/// contains a `BlocProvider` instance.
|
||||
static T of<T extends Bloc>(BuildContext context) {
|
||||
final type = _typeOf<BlocProvider<T>>();
|
||||
final BlocProvider<T> provider = context
|
||||
.ancestorInheritedElementForWidgetOfExactType(type)
|
||||
?.widget as BlocProvider<T>;
|
||||
|
||||
if (provider == null) {
|
||||
throw FlutterError(
|
||||
"""
|
||||
BlocProvider.of() called with a context that does not contain a Bloc of type $T.
|
||||
No ancestor could be found starting from the context that was passed to BlocProvider.of<$T>().
|
||||
This can happen if the context you use comes from a widget above the BlocProvider.
|
||||
This can also happen if you used BlocProviderTree and didn\'t explicity provide
|
||||
the BlocProvider types: BlocProvider(bloc: $T()) instead of BlocProvider<$T>(bloc: $T()).
|
||||
The context used was: $context
|
||||
""",
|
||||
);
|
||||
}
|
||||
return provider?.bloc;
|
||||
}
|
||||
|
||||
/// Clone the current [BlocProvider] with a new child [Widget].
|
||||
/// All other values, including [Key] and [Bloc] are preserved.
|
||||
BlocProvider<T> copyWith(Widget child) {
|
||||
return BlocProvider<T>(
|
||||
key: key,
|
||||
bloc: bloc,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
/// Necessary to obtain generic [Type]
|
||||
/// https://github.com/dart-lang/sdk/issues/11923
|
||||
static Type _typeOf<T>() => T;
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(BlocProvider oldWidget) => false;
|
||||
}
|
1
web_native/lib/bloc/bloc.dart
Normal file
1
web_native/lib/bloc/bloc.dart
Normal file
@ -0,0 +1 @@
|
||||
abstract class Bloc {}
|
5
web_native/lib/blocs/auth-bloc.dart
Normal file
5
web_native/lib/blocs/auth-bloc.dart
Normal file
@ -0,0 +1,5 @@
|
||||
import 'package:imagini/bloc/bloc.dart';
|
||||
|
||||
class AuthBloc extends Bloc {
|
||||
AuthBloc();
|
||||
}
|
2
web_native/lib/blocs/blocs.dart
Normal file
2
web_native/lib/blocs/blocs.dart
Normal file
@ -0,0 +1,2 @@
|
||||
export 'auth-bloc.dart';
|
||||
export 'pref-bloc.dart';
|
5
web_native/lib/blocs/pref-bloc.dart
Normal file
5
web_native/lib/blocs/pref-bloc.dart
Normal file
@ -0,0 +1,5 @@
|
||||
import 'package:imagini/bloc/bloc.dart';
|
||||
|
||||
class PrefBloc extends Bloc {
|
||||
PrefBloc();
|
||||
}
|
636
web_native/lib/components/roundedalertdialog.dart
Normal file
636
web_native/lib/components/roundedalertdialog.dart
Normal file
@ -0,0 +1,636 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// Examples can assume:
|
||||
// enum Department { treasury, state }
|
||||
|
||||
/// A material design dialog.
|
||||
///
|
||||
/// This dialog widget does not have any opinion about the contents of the
|
||||
/// dialog. Rather than using this widget directly, consider using [AlertDialog]
|
||||
/// or [SimpleDialog], which implement specific kinds of material design
|
||||
/// dialogs.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [AlertDialog], for dialogs that have a message and some buttons.
|
||||
/// * [SimpleDialog], for dialogs that offer a variety of options.
|
||||
/// * [showDialog], which actually displays the dialog and returns its result.
|
||||
/// * <https://material.google.com/components/dialogs.html>
|
||||
class Dialog extends StatelessWidget {
|
||||
/// Creates a dialog.
|
||||
///
|
||||
/// Typically used in conjunction with [showDialog].
|
||||
const Dialog({
|
||||
Key key,
|
||||
this.child,
|
||||
this.insetAnimationDuration: const Duration(milliseconds: 100),
|
||||
this.insetAnimationCurve: Curves.decelerate,
|
||||
}) : super(key: key);
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
///
|
||||
/// {@macro flutter.widgets.child}
|
||||
final Widget child;
|
||||
|
||||
/// The duration of the animation to show when the system keyboard intrudes
|
||||
/// into the space that the dialog is placed in.
|
||||
///
|
||||
/// Defaults to 100 milliseconds.
|
||||
final Duration insetAnimationDuration;
|
||||
|
||||
/// The curve to use for the animation shown when the system keyboard intrudes
|
||||
/// into the space that the dialog is placed in.
|
||||
///
|
||||
/// Defaults to [Curves.fastOutSlowIn].
|
||||
final Curve insetAnimationCurve;
|
||||
|
||||
Color _getColor(BuildContext context) {
|
||||
return Theme.of(context).dialogBackgroundColor;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new AnimatedPadding(
|
||||
padding: MediaQuery.of(context).viewInsets +
|
||||
const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0),
|
||||
duration: insetAnimationDuration,
|
||||
curve: insetAnimationCurve,
|
||||
child: new MediaQuery.removeViewInsets(
|
||||
removeLeft: true,
|
||||
removeTop: true,
|
||||
removeRight: true,
|
||||
removeBottom: true,
|
||||
context: context,
|
||||
child: new Center(
|
||||
child: new ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 280.0),
|
||||
child: new Material(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10.0)), side: BorderSide(color: Colors.white, width: 1.0, style: BorderStyle.solid)),
|
||||
elevation: 30.0,
|
||||
color: _getColor(context),
|
||||
type: MaterialType.card,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A material design alert dialog.
|
||||
///
|
||||
/// An alert dialog informs the user about situations that require
|
||||
/// acknowledgement. An alert dialog has an optional title and an optional list
|
||||
/// of actions. The title is displayed above the content and the actions are
|
||||
/// displayed below the content.
|
||||
///
|
||||
/// If the content is too large to fit on the screen vertically, the dialog will
|
||||
/// display the title and the actions and let the content overflow. Consider
|
||||
/// using a scrolling widget, such as [ListView], for [content] to avoid
|
||||
/// overflow.
|
||||
///
|
||||
/// For dialogs that offer the user a choice between several options, consider
|
||||
/// using a [SimpleDialog].
|
||||
///
|
||||
/// Typically passed as the child widget to [showDialog], which displays the
|
||||
/// dialog.
|
||||
///
|
||||
/// ## Sample code
|
||||
///
|
||||
/// This snippet shows a method in a [State] which, when called, displays a dialog box
|
||||
/// and returns a [Future] that completes when the dialog is dismissed.
|
||||
///
|
||||
/// ```dart
|
||||
/// Future<Null> _neverSatisfied() async {
|
||||
/// return showDialog<Null>(
|
||||
/// context: context,
|
||||
/// barrierDismissible: false, // user must tap button!
|
||||
/// builder: (BuildContext context) {
|
||||
/// return new AlertDialog(
|
||||
/// title: new Text('Rewind and remember'),
|
||||
/// content: new SingleChildScrollView(
|
||||
/// child: new ListBody(
|
||||
/// children: <Widget>[
|
||||
/// new Text('You will never be satisfied.'),
|
||||
/// new Text('You\’re like me. I’m never satisfied.'),
|
||||
/// ],
|
||||
/// ),
|
||||
/// ),
|
||||
/// actions: <Widget>[
|
||||
/// new FlatButton(
|
||||
/// child: new Text('Regret'),
|
||||
/// onPressed: () {
|
||||
/// Navigator.of(context).pop();
|
||||
/// },
|
||||
/// ),
|
||||
/// ],
|
||||
/// );
|
||||
/// },
|
||||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SimpleDialog], which handles the scrolling of the contents but has no [actions].
|
||||
/// * [Dialog], on which [AlertDialog] and [SimpleDialog] are based.
|
||||
/// * [showDialog], which actually displays the dialog and returns its result.
|
||||
/// * <https://material.google.com/components/dialogs.html#dialogs-alerts>
|
||||
class CustomAlertDialog extends StatelessWidget {
|
||||
/// Creates an alert dialog.
|
||||
///
|
||||
/// Typically used in conjunction with [showDialog].
|
||||
///
|
||||
/// The [contentPadding] must not be null. The [titlePadding] defaults to
|
||||
/// null, which implies a default that depends on the values of the other
|
||||
/// properties. See the documentation of [titlePadding] for details.
|
||||
const CustomAlertDialog({
|
||||
Key key,
|
||||
this.title,
|
||||
this.titlePadding,
|
||||
this.content,
|
||||
this.contentPadding: const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0),
|
||||
this.actions,
|
||||
this.semanticLabel,
|
||||
}) : assert(contentPadding != null),
|
||||
super(key: key);
|
||||
|
||||
/// The (optional) title of the dialog is displayed in a large font at the top
|
||||
/// of the dialog.
|
||||
///
|
||||
/// Typically a [Text] widget.
|
||||
final Widget title;
|
||||
|
||||
/// Padding around the title.
|
||||
///
|
||||
/// If there is no title, no padding will be provided. Otherwise, this padding
|
||||
/// is used.
|
||||
///
|
||||
/// This property defaults to providing 24 pixels on the top, left, and right
|
||||
/// of the title. If the [content] is not null, then no bottom padding is
|
||||
/// provided (but see [contentPadding]). If it _is_ null, then an extra 20
|
||||
/// pixels of bottom padding is added to separate the [title] from the
|
||||
/// [actions].
|
||||
final EdgeInsetsGeometry titlePadding;
|
||||
|
||||
/// The (optional) content of the dialog is displayed in the center of the
|
||||
/// dialog in a lighter font.
|
||||
///
|
||||
/// Typically, this is a [ListView] containing the contents of the dialog.
|
||||
/// Using a [ListView] ensures that the contents can scroll if they are too
|
||||
/// big to fit on the display.
|
||||
final Widget content;
|
||||
|
||||
/// Padding around the content.
|
||||
///
|
||||
/// If there is no content, no padding will be provided. Otherwise, padding of
|
||||
/// 20 pixels is provided above the content to separate the content from the
|
||||
/// title, and padding of 24 pixels is provided on the left, right, and bottom
|
||||
/// to separate the content from the other edges of the dialog.
|
||||
final EdgeInsetsGeometry contentPadding;
|
||||
|
||||
/// The (optional) set of actions that are displayed at the bottom of the
|
||||
/// dialog.
|
||||
///
|
||||
/// Typically this is a list of [FlatButton] widgets.
|
||||
///
|
||||
/// These widgets will be wrapped in a [ButtonBar], which introduces 8 pixels
|
||||
/// of padding on each side.
|
||||
///
|
||||
/// If the [title] is not null but the [content] _is_ null, then an extra 20
|
||||
/// pixels of padding is added above the [ButtonBar] to separate the [title]
|
||||
/// from the [actions].
|
||||
final List<Widget> actions;
|
||||
|
||||
/// The semantic label of the dialog used by accessibility frameworks to
|
||||
/// announce screen transitions when the dialog is opened and closed.
|
||||
///
|
||||
/// If this label is not provided, a semantic label will be infered from the
|
||||
/// [title] if it is not null. If there is no title, the label will be taken
|
||||
/// from [MaterialLocalizations.alertDialogLabel].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SemanticsConfiguration.isRouteName], for a description of how this
|
||||
/// value is used.
|
||||
final String semanticLabel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> children = <Widget>[];
|
||||
String label = semanticLabel;
|
||||
|
||||
if (title != null) {
|
||||
children.add(new Padding(
|
||||
padding: titlePadding ??
|
||||
new EdgeInsets.fromLTRB(
|
||||
24.0, 24.0, 24.0, content == null ? 20.0 : 0.0),
|
||||
child: new DefaultTextStyle(
|
||||
style: Theme.of(context).textTheme.title,
|
||||
child: new Semantics(child: title, namesRoute: true),
|
||||
),
|
||||
));
|
||||
} else {
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.iOS:
|
||||
label = semanticLabel;
|
||||
break;
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
label = semanticLabel ??
|
||||
MaterialLocalizations.of(context)?.alertDialogLabel;
|
||||
}
|
||||
}
|
||||
|
||||
if (content != null) {
|
||||
children.add(new Flexible(
|
||||
child: new Padding(
|
||||
padding: contentPadding,
|
||||
child: new DefaultTextStyle(
|
||||
style: Theme.of(context).textTheme.subhead,
|
||||
child: content,
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if (actions != null) {
|
||||
children.add(new ButtonTheme.bar(
|
||||
child: new ButtonBar(
|
||||
children: actions,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
Widget dialogChild = new IntrinsicWidth(
|
||||
child: new Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: children,
|
||||
),
|
||||
);
|
||||
|
||||
if (label != null)
|
||||
dialogChild =
|
||||
new Semantics(namesRoute: true, label: label, child: dialogChild);
|
||||
|
||||
return new Dialog(child: dialogChild);
|
||||
}
|
||||
}
|
||||
|
||||
/// An option used in a [SimpleDialog].
|
||||
///
|
||||
/// A simple dialog offers the user a choice between several options. This
|
||||
/// widget is commonly used to represent each of the options. If the user
|
||||
/// selects this option, the widget will call the [onPressed] callback, which
|
||||
/// typically uses [Navigator.pop] to close the dialog.
|
||||
///
|
||||
/// The padding on a [SimpleDialogOption] is configured to combine with the
|
||||
/// default [SimpleDialog.contentPadding] so that each option ends up 8 pixels
|
||||
/// from the other vertically, with 20 pixels of spacing between the dialog's
|
||||
/// title and the first option, and 24 pixels of spacing between the last option
|
||||
/// and the bottom of the dialog.
|
||||
///
|
||||
/// ## Sample code
|
||||
///
|
||||
/// ```dart
|
||||
/// new SimpleDialogOption(
|
||||
/// onPressed: () { Navigator.pop(context, Department.treasury); },
|
||||
/// child: const Text('Treasury department'),
|
||||
/// )
|
||||
/// ```
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SimpleDialog], for a dialog in which to use this widget.
|
||||
/// * [showDialog], which actually displays the dialog and returns its result.
|
||||
/// * [FlatButton], which are commonly used as actions in other kinds of
|
||||
/// dialogs, such as [AlertDialog]s.
|
||||
/// * <https://material.google.com/components/dialogs.html#dialogs-simple-dialogs>
|
||||
class SimpleDialogOption extends StatelessWidget {
|
||||
/// Creates an option for a [SimpleDialog].
|
||||
const SimpleDialogOption({
|
||||
Key key,
|
||||
this.onPressed,
|
||||
this.child,
|
||||
}) : super(key: key);
|
||||
|
||||
/// The callback that is called when this option is selected.
|
||||
///
|
||||
/// If this is set to null, the option cannot be selected.
|
||||
///
|
||||
/// When used in a [SimpleDialog], this will typically call [Navigator.pop]
|
||||
/// with a value for [showDialog] to complete its future with.
|
||||
final VoidCallback onPressed;
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
///
|
||||
/// Typically a [Text] widget.
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new InkWell(
|
||||
onTap: onPressed,
|
||||
child: new Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 24.0),
|
||||
child: child),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple material design dialog.
|
||||
///
|
||||
/// A simple dialog offers the user a choice between several options. A simple
|
||||
/// dialog has an optional title that is displayed above the choices.
|
||||
///
|
||||
/// Choices are normally represented using [SimpleDialogOption] widgets. If
|
||||
/// other widgets are used, see [contentPadding] for notes regarding the
|
||||
/// conventions for obtaining the spacing expected by Material Design.
|
||||
///
|
||||
/// For dialogs that inform the user about a situation, consider using an
|
||||
/// [AlertDialog].
|
||||
///
|
||||
/// Typically passed as the child widget to [showDialog], which displays the
|
||||
/// dialog.
|
||||
///
|
||||
/// ## Sample code
|
||||
///
|
||||
/// In this example, the user is asked to select between two options. These
|
||||
/// options are represented as an enum. The [showDialog] method here returns
|
||||
/// a [Future] that completes to a value of that enum. If the user cancels
|
||||
/// the dialog (e.g. by hitting the back button on Android, or tapping on the
|
||||
/// mask behind the dialog) then the future completes with the null value.
|
||||
///
|
||||
/// The return value in this example is used as the index for a switch statement.
|
||||
/// One advantage of using an enum as the return value and then using that to
|
||||
/// drive a switch statement is that the analyzer will flag any switch statement
|
||||
/// that doesn't mention every value in the enum.
|
||||
///
|
||||
/// ```dart
|
||||
/// Future<Null> _askedToLead() async {
|
||||
/// switch (await showDialog<Department>(
|
||||
/// context: context,
|
||||
/// builder: (BuildContext context) {
|
||||
/// return new SimpleDialog(
|
||||
/// title: const Text('Select assignment'),
|
||||
/// children: <Widget>[
|
||||
/// new SimpleDialogOption(
|
||||
/// onPressed: () { Navigator.pop(context, Department.treasury); },
|
||||
/// child: const Text('Treasury department'),
|
||||
/// ),
|
||||
/// new SimpleDialogOption(
|
||||
/// onPressed: () { Navigator.pop(context, Department.state); },
|
||||
/// child: const Text('State department'),
|
||||
/// ),
|
||||
/// ],
|
||||
/// );
|
||||
/// }
|
||||
/// )) {
|
||||
/// case Department.treasury:
|
||||
/// // Let's go.
|
||||
/// // ...
|
||||
/// break;
|
||||
/// case Department.state:
|
||||
/// // ...
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SimpleDialogOption], which are options used in this type of dialog.
|
||||
/// * [AlertDialog], for dialogs that have a row of buttons below the body.
|
||||
/// * [Dialog], on which [SimpleDialog] and [AlertDialog] are based.
|
||||
/// * [showDialog], which actually displays the dialog and returns its result.
|
||||
/// * <https://material.google.com/components/dialogs.html#dialogs-simple-dialogs>
|
||||
class SimpleDialog extends StatelessWidget {
|
||||
/// Creates a simple dialog.
|
||||
///
|
||||
/// Typically used in conjunction with [showDialog].
|
||||
///
|
||||
/// The [titlePadding] and [contentPadding] arguments must not be null.
|
||||
const SimpleDialog({
|
||||
Key key,
|
||||
this.title,
|
||||
this.titlePadding: const EdgeInsets.fromLTRB(24.0, 24.0, 24.0, 0.0),
|
||||
this.children,
|
||||
this.contentPadding: const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 16.0),
|
||||
this.semanticLabel,
|
||||
}) : assert(titlePadding != null),
|
||||
assert(contentPadding != null),
|
||||
super(key: key);
|
||||
|
||||
/// The (optional) title of the dialog is displayed in a large font at the top
|
||||
/// of the dialog.
|
||||
///
|
||||
/// Typically a [Text] widget.
|
||||
final Widget title;
|
||||
|
||||
/// Padding around the title.
|
||||
///
|
||||
/// If there is no title, no padding will be provided.
|
||||
///
|
||||
/// By default, this provides the recommend Material Design padding of 24
|
||||
/// pixels around the left, top, and right edges of the title.
|
||||
///
|
||||
/// See [contentPadding] for the conventions regarding padding between the
|
||||
/// [title] and the [children].
|
||||
final EdgeInsetsGeometry titlePadding;
|
||||
|
||||
/// The (optional) content of the dialog is displayed in a
|
||||
/// [SingleChildScrollView] underneath the title.
|
||||
///
|
||||
/// Typically a list of [SimpleDialogOption]s.
|
||||
final List<Widget> children;
|
||||
|
||||
/// Padding around the content.
|
||||
///
|
||||
/// By default, this is 12 pixels on the top and 16 pixels on the bottom. This
|
||||
/// is intended to be combined with children that have 24 pixels of padding on
|
||||
/// the left and right, and 8 pixels of padding on the top and bottom, so that
|
||||
/// the content ends up being indented 20 pixels from the title, 24 pixels
|
||||
/// from the bottom, and 24 pixels from the sides.
|
||||
///
|
||||
/// The [SimpleDialogOption] widget uses such padding.
|
||||
///
|
||||
/// If there is no [title], the [contentPadding] should be adjusted so that
|
||||
/// the top padding ends up being 24 pixels.
|
||||
final EdgeInsetsGeometry contentPadding;
|
||||
|
||||
/// The semantic label of the dialog used by accessibility frameworks to
|
||||
/// announce screen transitions when the dialog is opened and closed.
|
||||
///
|
||||
/// If this label is not provided, a semantic label will be infered from the
|
||||
/// [title] if it is not null. If there is no title, the label will be taken
|
||||
/// from [MaterialLocalizations.dialogLabel].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [SemanticsConfiguration.isRouteName], for a description of how this
|
||||
/// value is used.
|
||||
final String semanticLabel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> body = <Widget>[];
|
||||
String label = semanticLabel;
|
||||
|
||||
if (title != null) {
|
||||
body.add(new Padding(
|
||||
padding: titlePadding,
|
||||
child: new DefaultTextStyle(
|
||||
style: Theme.of(context).textTheme.title,
|
||||
child: new Semantics(namesRoute: true, child: title),
|
||||
)));
|
||||
} else {
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.iOS:
|
||||
label = semanticLabel;
|
||||
break;
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
label =
|
||||
semanticLabel ?? MaterialLocalizations.of(context)?.dialogLabel;
|
||||
}
|
||||
}
|
||||
|
||||
if (children != null) {
|
||||
body.add(new Flexible(
|
||||
child: new SingleChildScrollView(
|
||||
padding: contentPadding,
|
||||
child: new ListBody(children: children),
|
||||
)));
|
||||
}
|
||||
|
||||
Widget dialogChild = new IntrinsicWidth(
|
||||
stepWidth: 56.0,
|
||||
child: new ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 280.0),
|
||||
child: new Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: body,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (label != null)
|
||||
dialogChild = new Semantics(
|
||||
namesRoute: true,
|
||||
label: label,
|
||||
child: dialogChild,
|
||||
);
|
||||
return new Dialog(child: dialogChild);
|
||||
}
|
||||
}
|
||||
|
||||
class _DialogRoute<T> extends PopupRoute<T> {
|
||||
_DialogRoute({
|
||||
@required this.theme,
|
||||
bool barrierDismissible: true,
|
||||
this.barrierLabel,
|
||||
@required this.child,
|
||||
RouteSettings settings,
|
||||
}) : assert(barrierDismissible != null),
|
||||
_barrierDismissible = barrierDismissible,
|
||||
super(settings: settings);
|
||||
|
||||
final Widget child;
|
||||
final ThemeData theme;
|
||||
|
||||
@override
|
||||
Duration get transitionDuration => const Duration(milliseconds: 150);
|
||||
|
||||
@override
|
||||
bool get barrierDismissible => _barrierDismissible;
|
||||
final bool _barrierDismissible;
|
||||
|
||||
@override
|
||||
Color get barrierColor => Colors.black54;
|
||||
|
||||
@override
|
||||
final String barrierLabel;
|
||||
|
||||
@override
|
||||
Widget buildPage(BuildContext context, Animation<double> animation,
|
||||
Animation<double> secondaryAnimation) {
|
||||
return new SafeArea(
|
||||
child: new Builder(builder: (BuildContext context) {
|
||||
final Widget annotatedChild = new Semantics(
|
||||
child: child,
|
||||
scopesRoute: true,
|
||||
explicitChildNodes: true,
|
||||
);
|
||||
return theme != null
|
||||
? new Theme(data: theme, child: annotatedChild)
|
||||
: annotatedChild;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildTransitions(BuildContext context, Animation<double> animation,
|
||||
Animation<double> secondaryAnimation, Widget child) {
|
||||
return new FadeTransition(
|
||||
opacity: new CurvedAnimation(parent: animation, curve: Curves.easeOut),
|
||||
child: child);
|
||||
}
|
||||
}
|
||||
|
||||
/// Displays a dialog above the current contents of the app.
|
||||
///
|
||||
/// This function takes a `builder` which typically builds a [Dialog] widget.
|
||||
/// Content below the dialog is dimmed with a [ModalBarrier]. This widget does
|
||||
/// not share a context with the location that `showDialog` is originally
|
||||
/// called from. Use a [StatefulBuilder] or a custom [StatefulWidget] if the
|
||||
/// dialog needs to update dynamically.
|
||||
///
|
||||
/// The `context` argument is used to look up the [Navigator] and [Theme] for
|
||||
/// the dialog. It is only used when the method is called. Its corresponding
|
||||
/// widget can be safely removed from the tree before the dialog is closed.
|
||||
///
|
||||
/// The `child` argument is deprecated, and should be replaced with `builder`.
|
||||
///
|
||||
/// Returns a [Future] that resolves to the value (if any) that was passed to
|
||||
/// [Navigator.pop] when the dialog was closed.
|
||||
///
|
||||
/// The dialog route created by this method is pushed to the root navigator.
|
||||
/// If the application has multiple [Navigator] objects, it may be necessary to
|
||||
/// call `Navigator.of(context, rootNavigator: true).pop(result)` to close the
|
||||
/// dialog rather just 'Navigator.pop(context, result)`.
|
||||
///
|
||||
/// See also:
|
||||
/// * [AlertDialog], for dialogs that have a row of buttons below a body.
|
||||
/// * [SimpleDialog], which handles the scrolling of the contents and does
|
||||
/// not show buttons below its body.
|
||||
/// * [Dialog], on which [SimpleDialog] and [AlertDialog] are based.
|
||||
/// * <https://material.google.com/components/dialogs.html>
|
||||
Future<T> customShowDialog<T>({
|
||||
@required
|
||||
BuildContext context,
|
||||
bool barrierDismissible: true,
|
||||
@Deprecated(
|
||||
'Instead of using the "child" argument, return the child from a closure '
|
||||
'provided to the "builder" argument. This will ensure that the BuildContext '
|
||||
'is appropriate for widgets built in the dialog.')
|
||||
Widget child,
|
||||
WidgetBuilder builder,
|
||||
}) {
|
||||
assert(child == null || builder == null);
|
||||
return Navigator.of(context, rootNavigator: true).push(new _DialogRoute<T>(
|
||||
child: child ?? new Builder(builder: builder),
|
||||
theme: Theme.of(context, shadowThemeOnly: true),
|
||||
barrierDismissible: barrierDismissible,
|
||||
barrierLabel:
|
||||
MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
||||
));
|
||||
}
|
@ -1,117 +1,28 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:imagini/theme/style.dart';
|
||||
import 'package:imagini/routes.dart';
|
||||
import 'package:imagini/bloc/bloc-prov-tree.dart';
|
||||
import 'package:imagini/bloc/bloc-prov.dart';
|
||||
import 'package:imagini/blocs/blocs.dart';
|
||||
import 'blocs/blocs.dart';
|
||||
|
||||
void main() {
|
||||
runApp(MyApp());
|
||||
runApp(ExampleApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
// This widget is the root of your application.
|
||||
class ExampleApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Flutter Demo',
|
||||
theme: ThemeData(
|
||||
// This is the theme of your application.
|
||||
//
|
||||
// Try running your application with "flutter run". You'll see the
|
||||
// application has a blue toolbar. Then, without quitting the app, try
|
||||
// changing the primarySwatch below to Colors.green and then invoke
|
||||
// "hot reload" (press "r" in the console where you ran "flutter run",
|
||||
// or simply save your changes to "hot reload" in a Flutter IDE).
|
||||
// Notice that the counter didn't reset back to zero; the application
|
||||
// is not restarted.
|
||||
primarySwatch: Colors.blue,
|
||||
// This makes the visual density adapt to the platform that you run
|
||||
// the app on. For desktop platforms, the controls will be smaller and
|
||||
// closer together (more dense) than on mobile platforms.
|
||||
visualDensity: VisualDensity.adaptivePlatformDensity,
|
||||
),
|
||||
home: MyHomePage(title: 'Flutter Demo Home Page'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
MyHomePage({Key key, this.title}) : super(key: key);
|
||||
|
||||
// This widget is the home page of your application. It is stateful, meaning
|
||||
// that it has a State object (defined below) that contains fields that affect
|
||||
// how it looks.
|
||||
|
||||
// This class is the configuration for the state. It holds the values (in this
|
||||
// case the title) provided by the parent (in this case the App widget) and
|
||||
// used by the build method of the State. Fields in a Widget subclass are
|
||||
// always marked "final".
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
_MyHomePageState createState() => _MyHomePageState();
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
int _counter = 0;
|
||||
|
||||
void _incrementCounter() {
|
||||
setState(() {
|
||||
// This call to setState tells the Flutter framework that something has
|
||||
// changed in this State, which causes it to rerun the build method below
|
||||
// so that the display can reflect the updated values. If we changed
|
||||
// _counter without calling setState(), then the build method would not be
|
||||
// called again, and so nothing would appear to happen.
|
||||
_counter++;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// This method is rerun every time setState is called, for instance as done
|
||||
// by the _incrementCounter method above.
|
||||
//
|
||||
// The Flutter framework has been optimized to make rerunning build methods
|
||||
// fast, so that you can just rebuild anything that needs updating rather
|
||||
// than having to individually change instances of widgets.
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
// Here we take the value from the MyHomePage object that was created by
|
||||
// the App.build method, and use it to set our appbar title.
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: Center(
|
||||
// Center is a layout widget. It takes a single child and positions it
|
||||
// in the middle of the parent.
|
||||
child: Column(
|
||||
// Column is also a layout widget. It takes a list of children and
|
||||
// arranges them vertically. By default, it sizes itself to fit its
|
||||
// children horizontally, and tries to be as tall as its parent.
|
||||
//
|
||||
// Invoke "debug painting" (press "p" in the console, choose the
|
||||
// "Toggle Debug Paint" action from the Flutter Inspector in Android
|
||||
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
|
||||
// to see the wireframe for each widget.
|
||||
//
|
||||
// Column has various properties to control how it sizes itself and
|
||||
// how it positions its children. Here we use mainAxisAlignment to
|
||||
// center the children vertically; the main axis here is the vertical
|
||||
// axis because Columns are vertical (the cross axis would be
|
||||
// horizontal).
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'You have pushed the button this many times:',
|
||||
),
|
||||
Text(
|
||||
'$_counter',
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
),
|
||||
return BlocProviderTree(
|
||||
blocProviders: <BlocProvider>[
|
||||
BlocProvider<AuthBloc>(bloc: AuthBloc()),
|
||||
BlocProvider<PrefBloc>(bloc: PrefBloc()),
|
||||
],
|
||||
child: MaterialApp(
|
||||
title: 'ExampleApp',
|
||||
theme: appTheme(),
|
||||
initialRoute: '/',
|
||||
routes: routes,
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _incrementCounter,
|
||||
tooltip: 'Increment',
|
||||
child: Icon(Icons.add),
|
||||
), // This trailing comma makes auto-formatting nicer for build methods.
|
||||
);
|
||||
}
|
||||
}
|
||||
|
113
web_native/lib/main.dart.bak
Normal file
113
web_native/lib/main.dart.bak
Normal file
@ -0,0 +1,113 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() {
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Flutter Demo',
|
||||
theme: ThemeData(
|
||||
// This is the theme of your application.
|
||||
//
|
||||
// Try running your application with "flutter run". You'll see the
|
||||
// application has a blue toolbar. Then, without quitting the app, try
|
||||
// changing the primarySwatch below to Colors.green and then invoke
|
||||
// "hot reload" (press "r" in the console where you ran "flutter run",
|
||||
// or simply save your changes to "hot reload" in a Flutter IDE).
|
||||
// Notice that the counter didn't reset back to zero; the application
|
||||
// is not restarted.
|
||||
primarySwatch: Colors.blue,
|
||||
),
|
||||
home: MyHomePage(title: 'Flutter Demo Home Page'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
MyHomePage({Key key, this.title}) : super(key: key);
|
||||
|
||||
// This widget is the home page of your application. It is stateful, meaning
|
||||
// that it has a State object (defined below) that contains fields that affect
|
||||
// how it looks.
|
||||
|
||||
// This class is the configuration for the state. It holds the values (in this
|
||||
// case the title) provided by the parent (in this case the App widget) and
|
||||
// used by the build method of the State. Fields in a Widget subclass are
|
||||
// always marked "final".
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
_MyHomePageState createState() => _MyHomePageState();
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
int _counter = 0;
|
||||
|
||||
void _incrementCounter() {
|
||||
setState(() {
|
||||
// This call to setState tells the Flutter framework that something has
|
||||
// changed in this State, which causes it to rerun the build method below
|
||||
// so that the display can reflect the updated values. If we changed
|
||||
// _counter without calling setState(), then the build method would not be
|
||||
// called again, and so nothing would appear to happen.
|
||||
_counter++;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// This method is rerun every time setState is called, for instance as done
|
||||
// by the _incrementCounter method above.
|
||||
//
|
||||
// The Flutter framework has been optimized to make rerunning build methods
|
||||
// fast, so that you can just rebuild anything that needs updating rather
|
||||
// than having to individually change instances of widgets.
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
// Here we take the value from the MyHomePage object that was created by
|
||||
// the App.build method, and use it to set our appbar title.
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: Center(
|
||||
// Center is a layout widget. It takes a single child and positions it
|
||||
// in the middle of the parent.
|
||||
child: Column(
|
||||
// Column is also a layout widget. It takes a list of children and
|
||||
// arranges them vertically. By default, it sizes itself to fit its
|
||||
// children horizontally, and tries to be as tall as its parent.
|
||||
//
|
||||
// Invoke "debug painting" (press "p" in the console, choose the
|
||||
// "Toggle Debug Paint" action from the Flutter Inspector in Android
|
||||
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
|
||||
// to see the wireframe for each widget.
|
||||
//
|
||||
// Column has various properties to control how it sizes itself and
|
||||
// how it positions its children. Here we use mainAxisAlignment to
|
||||
// center the children vertically; the main axis here is the vertical
|
||||
// axis because Columns are vertical (the cross axis would be
|
||||
// horizontal).
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'You have pushed the button this many times:',
|
||||
),
|
||||
Text(
|
||||
'$_counter',
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _incrementCounter,
|
||||
tooltip: 'Increment',
|
||||
child: Icon(Icons.add),
|
||||
), // This trailing comma makes auto-formatting nicer for build methods.
|
||||
);
|
||||
}
|
||||
}
|
8
web_native/lib/models/contact.dart
Normal file
8
web_native/lib/models/contact.dart
Normal file
@ -0,0 +1,8 @@
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
class Contact {
|
||||
final String avatarUrl;
|
||||
final String name;
|
||||
|
||||
Contact({@required this.avatarUrl, @required this.name});
|
||||
}
|
8
web_native/lib/routes.dart
Normal file
8
web_native/lib/routes.dart
Normal file
@ -0,0 +1,8 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:imagini/screens/example1/examplescreen1.dart';
|
||||
import 'package:imagini/screens/example2/examplescreen2.dart';
|
||||
|
||||
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
|
||||
"/": (BuildContext context) => ExScreen1(),
|
||||
"/ExScreen2": (BuildContext context) => ExScreen2(),
|
||||
};
|
15
web_native/lib/screens/example1/components/body.dart
Normal file
15
web_native/lib/screens/example1/components/body.dart
Normal file
@ -0,0 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Body extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: RaisedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text('Go back!'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
20
web_native/lib/screens/example1/example-bloc.dart
Normal file
20
web_native/lib/screens/example1/example-bloc.dart
Normal file
@ -0,0 +1,20 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:imagini/models/contact.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:imagini/bloc/bloc.dart';
|
||||
|
||||
class ExampleBloc extends Bloc {
|
||||
StreamSubscription _audioPlayerStateSubscription;
|
||||
|
||||
Stream<String> get example => _exampleSubject.stream;
|
||||
Sink<String> get exampleSink => _exampleSubject.sink;
|
||||
final StreamController<String> _exampleSubject = StreamController<String>();
|
||||
|
||||
ExampleBloc();
|
||||
|
||||
void dispose() {
|
||||
_exampleSubject.close();
|
||||
}
|
||||
}
|
40
web_native/lib/screens/example1/examplescreen1.dart
Normal file
40
web_native/lib/screens/example1/examplescreen1.dart
Normal file
@ -0,0 +1,40 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:imagini/screens/example1/components/body.dart';
|
||||
import 'package:imagini/screens/example1/example-bloc.dart';
|
||||
import 'package:imagini/bloc/bloc-prov.dart';
|
||||
|
||||
class ExScreen1 extends StatefulWidget {
|
||||
@override
|
||||
_ExScreen1State createState() => _ExScreen1State();
|
||||
}
|
||||
|
||||
class _ExScreen1State extends State<ExScreen1> {
|
||||
ExampleBloc exampleBloc;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
exampleBloc = ExampleBloc();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
exampleBloc.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
bloc: exampleBloc,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("First Screen"),
|
||||
),
|
||||
body: Body(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
15
web_native/lib/screens/example2/components/body.dart
Normal file
15
web_native/lib/screens/example2/components/body.dart
Normal file
@ -0,0 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Body extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: RaisedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text('Go back!'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
20
web_native/lib/screens/example2/example2-bloc.dart
Normal file
20
web_native/lib/screens/example2/example2-bloc.dart
Normal file
@ -0,0 +1,20 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:imagini/models/contact.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:imagini/bloc/bloc.dart';
|
||||
|
||||
class Example2Bloc extends Bloc {
|
||||
StreamSubscription _audioPlayerStateSubscription;
|
||||
|
||||
Stream<String> get example => _exampleSubject.stream;
|
||||
Sink<String> get exampleSink => _exampleSubject.sink;
|
||||
final StreamController<String> _exampleSubject = StreamController<String>();
|
||||
|
||||
Example2Bloc();
|
||||
|
||||
void dispose() {
|
||||
_exampleSubject.close();
|
||||
}
|
||||
}
|
40
web_native/lib/screens/example2/examplescreen2.dart
Normal file
40
web_native/lib/screens/example2/examplescreen2.dart
Normal file
@ -0,0 +1,40 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:imagini/screens/example2/components/body.dart';
|
||||
import 'package:imagini/screens/example2/example2-bloc.dart';
|
||||
import 'package:imagini/bloc/bloc-prov.dart';
|
||||
|
||||
class ExScreen2 extends StatefulWidget {
|
||||
@override
|
||||
_ExScreen2State createState() => _ExScreen2State();
|
||||
}
|
||||
|
||||
class _ExScreen2State extends State<ExScreen2> {
|
||||
Example2Bloc example2Bloc;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
example2Bloc = Example2Bloc();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
example2Bloc.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
bloc: Example2Bloc(),
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("Second Screen"),
|
||||
),
|
||||
body: Body(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
11
web_native/lib/services/exampleapi.dart
Normal file
11
web_native/lib/services/exampleapi.dart
Normal file
@ -0,0 +1,11 @@
|
||||
import 'dart:async';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
Future<String> exampleApi(String orgid) async {
|
||||
http.Response response = await http.get(
|
||||
Uri.encodeFull("https://www.example.com/api"),
|
||||
);
|
||||
print("Respone ${response.body.toString()}");
|
||||
//Returns 'true' or 'false' as a String
|
||||
return response.body;
|
||||
}
|
13
web_native/lib/theme/style.dart
Normal file
13
web_native/lib/theme/style.dart
Normal file
@ -0,0 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
ThemeData appTheme() {
|
||||
return ThemeData(
|
||||
primaryColor: Colors.white,
|
||||
accentColor: Colors.orange,
|
||||
hintColor: Colors.white,
|
||||
dividerColor: Colors.white,
|
||||
buttonColor: Colors.white,
|
||||
scaffoldBackgroundColor: Colors.black,
|
||||
canvasColor: Colors.black,
|
||||
);
|
||||
}
|
@ -1,153 +1,385 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "12.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.40.6"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.13"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.5.0-nullsafety.1"
|
||||
version: "2.5.0-nullsafety.3"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0-nullsafety.1"
|
||||
version: "2.1.0-nullsafety.3"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0-nullsafety.3"
|
||||
version: "1.1.0-nullsafety.5"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0-nullsafety.1"
|
||||
version: "1.2.0-nullsafety.3"
|
||||
cli_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0-nullsafety.1"
|
||||
version: "1.1.0-nullsafety.3"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.15.0-nullsafety.3"
|
||||
version: "1.15.0-nullsafety.5"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
coverage:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: coverage
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.14.2"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cupertino_icons
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.0.2"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0-nullsafety.1"
|
||||
version: "1.2.0-nullsafety.3"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.0-nullsafety.4"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_driver:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
fuchsia_remote_debug_protocol:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
integration_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.9.2+2"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.4"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.3-nullsafety.3"
|
||||
json_rpc_2:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: json_rpc_2
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.11.4"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.10-nullsafety.1"
|
||||
version: "0.12.10-nullsafety.3"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0-nullsafety.3"
|
||||
version: "1.3.0-nullsafety.6"
|
||||
node_interop:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: node_interop
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
node_io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: node_io
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.3"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0-nullsafety.1"
|
||||
version: "1.8.0-nullsafety.3"
|
||||
pedantic:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pedantic
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.10.0-nullsafety.3"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0-nullsafety.4"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.0-nullsafety.3"
|
||||
process:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: process
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.0-nullsafety.4"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.4.4"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_map_stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_map_stack_trace
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0-nullsafety.4"
|
||||
source_maps:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_maps
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.10.10-nullsafety.3"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0-nullsafety.2"
|
||||
version: "1.8.0-nullsafety.4"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.10.0-nullsafety.1"
|
||||
version: "1.10.0-nullsafety.6"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0-nullsafety.1"
|
||||
version: "2.1.0-nullsafety.3"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0-nullsafety.1"
|
||||
version: "1.1.0-nullsafety.3"
|
||||
sync_http:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sync_http
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0-nullsafety.1"
|
||||
version: "1.2.0-nullsafety.3"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.19-nullsafety.2"
|
||||
version: "0.2.19-nullsafety.6"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.12-nullsafety.9"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0-nullsafety.3"
|
||||
version: "1.3.0-nullsafety.5"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0-nullsafety.3"
|
||||
version: "2.1.0-nullsafety.5"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.5.0"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.9.7+15"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
webdriver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webdriver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
sdks:
|
||||
dart: ">=2.10.0-110 <2.11.0"
|
||||
dart: ">=2.12.0-0.0 <3.0.0"
|
||||
|
@ -1,4 +1,4 @@
|
||||
name: Imagini
|
||||
name: imagini
|
||||
description: A new Flutter project.
|
||||
|
||||
# The following line prevents the package from being accidentally published to
|
||||
@ -27,11 +27,13 @@ dependencies:
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.0
|
||||
cupertino_icons: ^1.0.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
integration_test:
|
||||
sdk: flutter
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
@ -8,7 +8,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:web_native/main.dart';
|
||||
import 'package:imagini/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
|
BIN
web_native/web/favicon.png
Normal file
BIN
web_native/web/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 917 B |
BIN
web_native/web/icons/Icon-192.png
Normal file
BIN
web_native/web/icons/Icon-192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
web_native/web/icons/Icon-512.png
Normal file
BIN
web_native/web/icons/Icon-512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
45
web_native/web/index.html
Normal file
45
web_native/web/index.html
Normal file
@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
If you are serving your web app in a path other than the root, change the
|
||||
href value below to reflect the base path you are serving from.
|
||||
|
||||
The path provided below has to start and end with a slash "/" in order for
|
||||
it to work correctly.
|
||||
|
||||
Fore more details:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||
-->
|
||||
<base href="/">
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||
<meta name="description" content="A new Flutter project.">
|
||||
|
||||
<!-- iOS meta tags & icons -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="imagini">
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||
|
||||
<title>imagini</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
</head>
|
||||
<body>
|
||||
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||
application. For more information, see:
|
||||
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('flutter-first-frame', function () {
|
||||
navigator.serviceWorker.register('flutter_service_worker.js');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script src="main.dart.js" type="application/javascript"></script>
|
||||
</body>
|
||||
</html>
|
23
web_native/web/manifest.json
Normal file
23
web_native/web/manifest.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "imagini",
|
||||
"short_name": "imagini",
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"background_color": "#0175C2",
|
||||
"theme_color": "#0175C2",
|
||||
"description": "A new Flutter project.",
|
||||
"orientation": "portrait-primary",
|
||||
"prefer_related_applications": false,
|
||||
"icons": [
|
||||
{
|
||||
"src": "icons/Icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "icons/Icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
Reference in New Issue
Block a user