This commit is contained in:
2021-01-07 21:45:59 -05:00
parent 67e7bf9f5a
commit 04924ead5c
28 changed files with 676 additions and 288 deletions

View File

@@ -1,113 +0,0 @@
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.
);
}
}

View File

@@ -1,8 +1,10 @@
import 'package:flutter/widgets.dart';
import 'package:imagini/screens/example1/examplescreen1.dart';
import 'package:imagini/screens/photo/photoscreen.dart';
import 'package:imagini/screens/upload/uploadscreen.dart';
import 'package:imagini/screens/example2/examplescreen2.dart';
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
"/": (BuildContext context) => ExScreen1(),
"/": (BuildContext context) => PhotoScreen(),
"/Upload": (BuildContext context) => UploadScreen(),
"/ExScreen2": (BuildContext context) => ExScreen2(),
};

View File

@@ -1,40 +0,0 @@
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(),
),
);
}
}

View 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();
}
}

View 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(),
),
);
}
}

View 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.pushNamed(context, '/Upload');
},
child: Text('Page Two!'),
),
);
}
}

View File

@@ -5,14 +5,14 @@ import 'package:imagini/models/contact.dart';
import 'package:flutter/material.dart';
import 'package:imagini/bloc/bloc.dart';
class ExampleBloc extends Bloc {
class PhotoBloc extends Bloc {
StreamSubscription _audioPlayerStateSubscription;
Stream<String> get example => _exampleSubject.stream;
Sink<String> get exampleSink => _exampleSubject.sink;
final StreamController<String> _exampleSubject = StreamController<String>();
ExampleBloc();
PhotoBloc();
void dispose() {
_exampleSubject.close();

View File

@@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:imagini/screens/photo/components/body.dart';
import 'package:imagini/screens/photo/photo-bloc.dart';
import 'package:imagini/bloc/bloc-prov.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
class PhotoScreen extends StatefulWidget {
@override
_PhotoScreenState createState() => _PhotoScreenState();
}
class _PhotoScreenState extends State<PhotoScreen> {
PhotoBloc exampleBloc;
@override
void initState() {
super.initState();
exampleBloc = PhotoBloc();
}
@override
void dispose() {
exampleBloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocProvider(
bloc: exampleBloc,
child: PlatformScaffold(
appBar: PlatformAppBar(
title: Text('Photos'),
cupertino: (_, __) => CupertinoNavigationBarData(
// Issue with cupertino where a bar with no transparency
// will push the list down. Adding some alpha value fixes it (in a hacky way)
backgroundColor: Colors.lightGreen.withAlpha(254),
),
),
body: Body(),
),
);
}
}

View 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 UploadBloc extends Bloc {
StreamSubscription _audioPlayerStateSubscription;
Stream<String> get example => _exampleSubject.stream;
Sink<String> get exampleSink => _exampleSubject.sink;
final StreamController<String> _exampleSubject = StreamController<String>();
UploadBloc();
void dispose() {
_exampleSubject.close();
}
}

View File

@@ -0,0 +1,197 @@
import 'package:cross_file/cross_file.dart' show XFile;
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:imagini/bloc/bloc-prov.dart';
import 'package:imagini/screens/upload/upload-bloc.dart';
import 'package:tus_client/tus_client.dart';
import 'package:url_launcher/url_launcher.dart';
class UploadScreen extends StatefulWidget {
@override
_UploadScreenState createState() => _UploadScreenState();
}
class _UploadScreenState extends State<UploadScreen> {
UploadBloc exampleBloc;
double _progress = 0;
XFile _file;
TusClient _client;
Uri _fileUrl;
@override
void initState() {
super.initState();
exampleBloc = UploadBloc();
}
@override
void dispose() {
exampleBloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocProvider(
bloc: exampleBloc,
child: PlatformScaffold(
appBar: PlatformAppBar(
title: Text('Uploads'),
cupertino: (_, __) => CupertinoNavigationBarData(
// Issue with cupertino where a bar with no transparency
// will push the list down. Adding some alpha value fixes it (in a hacky way)
backgroundColor: Colors.lightGreen.withAlpha(254),
),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
SizedBox(height: 12),
Padding(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2),
child: Text(
"This demo uses TUS client to upload a file",
style: TextStyle(fontSize: 18),
),
),
Padding(
padding: const EdgeInsets.all(6),
child: Card(
color: Colors.teal,
child: InkWell(
onTap: () async {
_file =
await _getXFile(await FilePicker.platform.pickFiles());
setState(() {
_progress = 0;
_fileUrl = null;
});
},
child: Container(
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
Icon(Icons.cloud_upload, color: Colors.white, size: 60),
Text(
"Upload a file",
style: TextStyle(fontSize: 25, color: Colors.white),
),
],
),
),
),
),
),
Padding(
padding: const EdgeInsets.all(8),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
onPressed: _file == null
? null
: () async {
// Create a client
print("Create a client");
_client = TusClient(
Uri.parse("https://master.tus.io/files/"),
_file,
store: TusMemoryStore(),
);
print("Starting upload");
await _client.upload(
onComplete: () async {
print("Completed!");
setState(() => _fileUrl = _client.uploadUrl);
},
onProgress: (progress) {
print("Progress: $progress");
setState(() => _progress = progress);
},
);
},
child: Text("Upload"),
),
),
SizedBox(width: 8),
Expanded(
child: RaisedButton(
onPressed: _progress == 0
? null
: () async {
_client.pause();
},
child: Text("Pause"),
),
),
],
),
),
Stack(
children: <Widget>[
Container(
margin: const EdgeInsets.all(8),
padding: const EdgeInsets.all(1),
color: Colors.grey,
width: double.infinity,
child: Text(" "),
),
FractionallySizedBox(
widthFactor: _progress / 100,
child: Container(
margin: const EdgeInsets.all(8),
padding: const EdgeInsets.all(1),
color: Colors.green,
child: Text(" "),
),
),
Container(
margin: const EdgeInsets.all(8),
padding: const EdgeInsets.all(1),
width: double.infinity,
child: Text("Progress: ${_progress.toStringAsFixed(1)}%"),
),
],
),
GestureDetector(
onTap: _progress != 100
? null
: () async {
await launch(_fileUrl.toString());
},
child: Container(
color: _progress == 100 ? Colors.green : Colors.grey,
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
child:
Text(_progress == 100 ? "Link to view:\n $_fileUrl" : "-"),
),
),
],
),
),
),
);
}
Future<XFile> _getXFile(FilePickerResult result) async {
if (result != null) {
final chosenFile = result.files.first;
if (chosenFile.path != null) {
// Android, iOS, Desktop
return XFile(chosenFile.path);
} else {
// Web
return XFile.fromData(
chosenFile.bytes,
name: chosenFile.name,
);
}
}
return null;
}
}

View File

@@ -7,7 +7,7 @@ ThemeData appTheme() {
hintColor: Colors.white,
dividerColor: Colors.white,
buttonColor: Colors.white,
scaffoldBackgroundColor: Colors.black,
canvasColor: Colors.black,
scaffoldBackgroundColor: Colors.blue,
canvasColor: Colors.blue,
);
}
}

View File

@@ -92,6 +92,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.14.2"
cross_file:
dependency: transitive
description:
name: cross_file
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
crypto:
dependency: transitive
description:
@@ -120,6 +127,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.0-nullsafety.4"
file_picker:
dependency: "direct main"
description:
name: file_picker
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
flutter:
dependency: "direct main"
description: flutter
@@ -130,11 +144,30 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_platform_widgets:
dependency: "direct main"
description:
name: flutter_platform_widgets
url: "https://pub.dartlang.org"
source: hosted
version: "0.72.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.11"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
@@ -147,6 +180,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
http:
dependency: transitive
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.2"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.4"
integration_test:
dependency: "direct dev"
description: flutter
@@ -236,6 +283,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0-nullsafety.4"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
pool:
dependency: transitive
description:
@@ -332,6 +386,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.12-nullsafety.9"
tus_client:
dependency: "direct main"
description:
name: tus_client
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
typed_data:
dependency: transitive
description:
@@ -339,6 +400,48 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0-nullsafety.5"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "5.7.10"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+4"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+9"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.9"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.5+1"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+3"
vector_math:
dependency: transitive
description:
@@ -383,3 +486,4 @@ packages:
version: "2.2.1"
sdks:
dart: ">=2.12.0-0.0 <3.0.0"
flutter: ">=1.22.0 <2.0.0"

View File

@@ -23,10 +23,10 @@ environment:
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
flutter_platform_widgets: ^0.72.0
tus_client: ^0.1.1
file_picker: ^2.1.5
url_launcher: ^5.7.10
cupertino_icons: ^1.0.1
dev_dependencies: