Skip to content
This repository has been archived by the owner on Jan 10, 2023. It is now read-only.

Upgrade to Flutter 2 and null-safety #49

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
.atom/
.idea/
*.iml
.vscode/

# dart
.packages
.pub
packages
pubspec.lock
.dart_tool/

# flutter
build/
Expand Down
1 change: 1 addition & 0 deletions example/ios/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ Icon?
/Flutter/Flutter.framework
/Flutter/Generated.xcconfig
/ServiceDefinitions.json
/Flutter/flutter_export_environment.sh

Pods/
2 changes: 1 addition & 1 deletion example/ios/Flutter/AppFrameworkInfo.plist
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
<string>arm64</string>
</array>
<key>MinimumOSVersion</key>
<string>8.0</string>
<string>9.0</string>
</dict>
</plist>
24 changes: 3 additions & 21 deletions example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@

/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
Expand All @@ -30,8 +25,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -41,15 +34,12 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
Expand All @@ -63,8 +53,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -74,10 +62,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
Expand Down Expand Up @@ -192,7 +177,6 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -212,7 +196,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
Expand Down Expand Up @@ -265,7 +249,6 @@
/* Begin XCBuildConfiguration section */
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
Expand Down Expand Up @@ -309,7 +292,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
Expand All @@ -319,7 +302,6 @@
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
Expand Down Expand Up @@ -357,7 +339,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 11 additions & 10 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void main() {

class ChatScreen extends StatefulWidget {
/// Creates a widget that watches stores.
ChatScreen({Key key}) : super(key: key);
ChatScreen({Key? key}) : super(key: key);

@override
ChatScreenState createState() => new ChatScreenState();
Expand All @@ -33,8 +33,8 @@ class ChatScreen extends StatefulWidget {
class ChatScreenState extends State<ChatScreen>
with StoreWatcherMixin<ChatScreen> {
// Never write to these stores directly. Use Actions.
ChatMessageStore messageStore;
ChatUserStore chatUserStore;
late ChatMessageStore messageStore;
late ChatUserStore chatUserStore;

final TextEditingController msgController = new TextEditingController();

Expand All @@ -52,23 +52,24 @@ class ChatScreenState extends State<ChatScreen>

// Demonstrates using a custom change handler.
messageStore =
listenToStore(messageStoreToken, handleChatMessageStoreChanged);
listenToStore(messageStoreToken, handleChatMessageStoreChanged)
as ChatMessageStore;

// Demonstrates using the default handler, which just calls setState().
chatUserStore = listenToStore(userStoreToken);
chatUserStore = listenToStore(userStoreToken) as ChatUserStore;
}

void handleChatMessageStoreChanged(Store store) {
ChatMessageStore messageStore = store;
ChatMessageStore messageStore = store as ChatMessageStore;
if (messageStore.currentMessage.isEmpty) {
msgController.clear();
msgController.clear();
}
setState(() {});
}

Widget _buildTextComposer(BuildContext context, ChatMessageStore messageStore,
ChatUserStore userStore) {
final ValueChanged<String> commitMessage = (String _) {
final ValueChanged<String?> commitMessage = (String? _) {
commitCurrentMessageAction(userStore.me);
};

Expand Down Expand Up @@ -122,8 +123,8 @@ class ChatMessageListItem extends StatefulWidget {

class ChatMessageListItemState extends State<ChatMessageListItem>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
Animation<double> _animation;
late AnimationController _animationController;
late Animation<double> _animation;

@override
void initState() {
Expand Down
18 changes: 9 additions & 9 deletions example/lib/stores.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,29 @@

import 'dart:math' show Random;

import 'package:flutter/material.dart';
import 'package:flutter/material.dart' show Color, Colors;
import 'package:flutter_flux/flutter_flux.dart';

class ChatUser {
ChatUser({this.name, this.color});
ChatUser({required this.name, required this.color});
final String name;
final Color color;
}

class ChatMessage {
ChatMessage({this.sender, this.text});
ChatMessage({required this.sender, required this.text});
final ChatUser sender;
final String text;
}

class ChatMessageStore extends Store {
ChatMessageStore() {
triggerOnAction(setCurrentMessageAction, (String value) {
_currentMessage = value;
triggerOnAction(setCurrentMessageAction, (String? value) {
_currentMessage = value ?? '';
});
triggerOnAction(commitCurrentMessageAction, (ChatUser me) {
triggerOnAction(commitCurrentMessageAction, (ChatUser? me) {
final ChatMessage message =
new ChatMessage(sender: me, text: _currentMessage);
new ChatMessage(sender: me!, text: _currentMessage);
_messages.add(message);
_currentMessage = '';
});
Expand All @@ -46,12 +46,12 @@ class ChatUserStore extends Store {
ChatUserStore() {
final String name = "Guest${new Random().nextInt(1000)}";
final Color color =
Colors.accents[new Random().nextInt(Colors.accents.length)][700];
Colors.accents[new Random().nextInt(Colors.accents.length)][700]!;
_me = new ChatUser(name: name, color: color);
// This store does not currently handle any actions.
}

ChatUser _me;
late ChatUser _me;
ChatUser get me => _me;
}

Expand Down
3 changes: 3 additions & 0 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ dev_dependencies:

flutter:
uses-material-design: true

environment:
sdk: '>=2.12.0 <3.0.0'
14 changes: 7 additions & 7 deletions lib/src/action.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ typedef void OnData<T>(T event);
/// when a consumer needs to check state changes immediately after invoking an
/// action.
///
class Action<T> implements Function {
List<OnData<T>> _listeners = <OnData<T>>[];
class Action<T> {
List<OnData<T?>> _listeners = <OnData<T?>>[];

/// Dispatch this [Action] to all listeners. If a payload is supplied, it will
/// be passed to each listener's callback, otherwise null will be passed.
Future<List<dynamic>> call([T payload]) {
Future<List<dynamic>> call([T? payload]) {
// Invoke all listeners in a microtask to enable waiting on futures. The
// microtask queue is emptied before the event loop continues. This ensures
// synchronous listeners are invoked in the current tick of the event loop
Expand All @@ -60,7 +60,7 @@ class Action<T> implements Function {
// for stream-based actions vs. 0.14 ms for this action implementation.
return Future.wait<dynamic>(
_listeners.map(
(OnData<T> l) => new Future<dynamic>.microtask(() => l(payload))
(OnData<T?> l) => new Future<dynamic>.microtask(() => l(payload)),
),
);
}
Expand All @@ -74,7 +74,7 @@ class Action<T> implements Function {
/// dispatched. A payload of type [T] will be passed to the callback if
/// supplied at dispatch time, otherwise null will be passed. Returns an
/// [ActionSubscription] which provides means to cancel the subscription.
ActionSubscription listen(OnData<T> onData) {
ActionSubscription listen(OnData<T?> onData) {
_listeners.add(onData);
return new ActionSubscription(() => _listeners.remove(onData));
}
Expand All @@ -84,14 +84,14 @@ typedef void _OnCancel();

/// A subscription used to cancel registered listeners to an [Action].
class ActionSubscription {
final _OnCancel _onCancel;
final _OnCancel? _onCancel;

ActionSubscription(this._onCancel);

/// Cancel this subscription to an [Action]
void cancel() {
if (_onCancel != null) {
_onCancel();
_onCancel!();
}
}
}
27 changes: 15 additions & 12 deletions lib/src/store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,20 @@ class Store {
/// As an example, [transformer] could be used to throttle the number of
/// triggers this [Store] emits for state that may update extremely frequently
/// (like scroll position).
Store.withTransformer(StreamTransformer<dynamic, dynamic> transformer) {
Store.withTransformer(StreamTransformer<Store, dynamic> transformer) {
_streamController = new StreamController<Store>();

// apply a transform to the stream if supplied
_stream =
_streamController.stream.transform<dynamic>(transformer).asBroadcastStream();
_stream = _streamController.stream
.transform<dynamic>(transformer)
.asBroadcastStream() as Stream<Store>;
}

/// Stream controller for [_stream]. Used by [trigger].
StreamController<Store> _streamController;
late StreamController<Store> _streamController;

/// Broadcast stream of "data updated" events. Listened to in [listen].
Stream<Store> _stream;
late Stream<Store> _stream;

void dispose() {
_streamController.close();
Expand All @@ -79,10 +80,9 @@ class Store {
/// A convenience method for listening to an [action] and triggering
/// automatically. The callback doesn't call return, so the return
/// type of onAction is null.
void triggerOnAction<T>(Action<T> action,
[dynamic onAction(T payload)]) {
void triggerOnAction<T>(Action<T> action, [dynamic onAction(T? payload)?]) {
if (onAction != null) {
action.listen((T payload) async {
action.listen((T? payload) async {
await onAction(payload);
trigger();
});
Expand All @@ -102,7 +102,6 @@ class Store {
/// void (null) or true.
void triggerOnConditionalAction<T>(
Action<T> action, FutureOr<bool> onAction(T payload)) {
assert(action != null);
action.listen((dynamic payload) async {
// Action functions must return bool, or a Future<bool>.
dynamic result = onAction(payload);
Expand All @@ -123,8 +122,12 @@ class Store {
/// Each time this `Store` triggers (by calling [trigger]), indicating that
/// data has been mutated, [onData] will be called.
StreamSubscription<Store> listen(void onData(Store event),
{Function onError, void onDone(), bool cancelOnError}) {
return _stream.listen(onData,
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
{Function? onError, void onDone()?, bool? cancelOnError}) {
return _stream.listen(
onData,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
}
}
Loading