Merge pull request #109 from tommyxchow/dev

Release v1.2.2
This commit is contained in:
Tommy Chow 2022-04-09 00:08:49 -04:00 • committed by GitHub
commit edaccc2fb4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 180 additions and 206 deletions

View file

@ -85,7 +85,7 @@ SPEC CHECKSUMS:
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
webview_flutter_wkwebview: 005fbd90c888a42c5690919a1527ecc6649e1162
webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c

View file

@ -64,18 +64,18 @@ abstract class _AuthBase with Store {
await _storage.write(key: _defaultTokenKey, value: _token);
}
} else {
// Validate the existing token.
_tokenIsValid = await twitchApi.validateToken(token: _token!);
// If the token is invalid, logout.
if (!_tokenIsValid) return await logout();
// Initialize the user store.
await user.init(headers: headersTwitch);
if (user.details != null) _isLoggedIn = true;
}
// Validate the token.
_tokenIsValid = await twitchApi.validateToken(token: _token!);
// If the token is invalid, logout.
if (!_tokenIsValid) await logout();
_error = null;
} catch (e) {
debugPrint(e.toString());

View file

@ -74,6 +74,9 @@ void main() async {
);
}
// Navigator key for sleep timer. Allows navigation popping without context.
final navigatorKey = GlobalKey<NavigatorState>();
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@ -164,6 +167,7 @@ class MyApp extends StatelessWidget {
? ThemeMode.light
: ThemeMode.dark,
home: const Home(),
navigatorKey: navigatorKey,
);
},
);

View file

@ -581,10 +581,7 @@ class IRCMessage {
return TextSpan(
text: text,
style: style?.copyWith(color: Colors.blue),
recognizer: TapGestureRecognizer()
..onTap = () async {
if (await canLaunch(text)) launch(text);
},
recognizer: TapGestureRecognizer()..onTap = () => launch(text),
);
} else {
return TextSpan(text: text, style: style);

View file

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:frosty/screens/channel/chat/emote_menu/emote_menu.dart';
import 'package:frosty/screens/channel/chat/widgets/chat_bottom_bar.dart';
@ -14,103 +15,109 @@ class Chat extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Observer(
builder: (context) => Column(
children: [
Expanded(
child: GestureDetector(
onTap: () {
if (chatStore.assetsStore.showEmoteMenu) {
chatStore.assetsStore.showEmoteMenu = false;
} else if (chatStore.textFieldFocusNode.hasFocus) {
chatStore.textFieldFocusNode.unfocus();
}
},
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: [
MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: chatStore.settings.messageScale),
child: DefaultTextStyle(
style: DefaultTextStyle.of(context).style.copyWith(fontSize: chatStore.settings.fontSize),
child: Observer(
builder: (context) {
final showDividers = chatStore.settings.showChatMessageDividers;
builder: (context) {
SchedulerBinding.instance?.addPostFrameCallback((_) {
if (chatStore.scrollController.hasClients) chatStore.scrollController.jumpTo(chatStore.scrollController.position.maxScrollExtent);
});
return ListView.separated(
padding: const EdgeInsets.symmetric(vertical: 5.0),
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
itemCount: chatStore.messages.length,
controller: chatStore.scrollController,
separatorBuilder: (context, index) => showDividers
? Divider(
height: chatStore.settings.messageSpacing,
thickness: 1.0,
)
: SizedBox(height: chatStore.settings.messageSpacing),
itemBuilder: (context, index) => Observer(
builder: (context) {
final message = chatStore.messages[index];
final chatMessage = ChatMessage(
ircMessage: message,
assetsStore: chatStore.assetsStore,
settingsStore: chatStore.settings,
);
return Column(
children: [
Expanded(
child: GestureDetector(
onTap: () {
if (chatStore.assetsStore.showEmoteMenu) {
chatStore.assetsStore.showEmoteMenu = false;
} else if (chatStore.textFieldFocusNode.hasFocus) {
chatStore.textFieldFocusNode.unfocus();
}
},
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: [
MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: chatStore.settings.messageScale),
child: DefaultTextStyle(
style: DefaultTextStyle.of(context).style.copyWith(fontSize: chatStore.settings.fontSize),
child: Observer(
builder: (context) {
final showDividers = chatStore.settings.showChatMessageDividers;
if (message.user != null && message.user != chatStore.auth.user.details?.login) {
return InkWell(
onTap: () {
FocusScope.of(context).unfocus();
if (chatStore.assetsStore.showEmoteMenu) chatStore.assetsStore.showEmoteMenu = false;
},
onLongPress: () => showModalBottomSheet(
context: context,
builder: (context) => ChatUserModal(
chatStore: chatStore,
username: message.user!,
userId: message.tags['user-id']!,
displayName: message.tags['display-name']!,
),
),
child: chatMessage,
return ListView.separated(
padding: const EdgeInsets.symmetric(vertical: 5.0),
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
itemCount: chatStore.messages.length,
controller: chatStore.scrollController,
separatorBuilder: (context, index) => showDividers
? Divider(
height: chatStore.settings.messageSpacing,
thickness: 1.0,
)
: SizedBox(height: chatStore.settings.messageSpacing),
itemBuilder: (context, index) => Observer(
builder: (context) {
final message = chatStore.messages[index];
final chatMessage = ChatMessage(
ircMessage: message,
assetsStore: chatStore.assetsStore,
settingsStore: chatStore.settings,
);
}
return chatMessage;
},
),
);
},
if (message.user != null && message.user != chatStore.auth.user.details?.login) {
return InkWell(
onTap: () {
FocusScope.of(context).unfocus();
if (chatStore.assetsStore.showEmoteMenu) chatStore.assetsStore.showEmoteMenu = false;
},
onLongPress: () => showModalBottomSheet(
context: context,
builder: (context) => ChatUserModal(
chatStore: chatStore,
username: message.user!,
userId: message.tags['user-id']!,
displayName: message.tags['display-name']!,
),
),
child: chatMessage,
);
}
return chatMessage;
},
),
);
},
),
),
),
),
Observer(
builder: (_) => AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: chatStore.autoScroll
? null
: Container(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
width: double.infinity,
child: ElevatedButton.icon(
onPressed: chatStore.resumeScroll,
label: const Text('Resume Scroll'),
icon: const Icon(Icons.arrow_circle_down),
Observer(
builder: (_) => AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: chatStore.autoScroll
? null
: Container(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
width: double.infinity,
child: ElevatedButton.icon(
onPressed: chatStore.resumeScroll,
label: const Text('Resume Scroll'),
icon: const Icon(Icons.arrow_circle_down),
),
),
),
),
),
),
],
],
),
),
),
),
if (chatStore.settings.showBottomBar) ChatBottomBar(chatStore: chatStore),
if (chatStore.assetsStore.showEmoteMenu)
SizedBox(
height: MediaQuery.of(context).size.height / 3,
child: EmoteMenu(chatStore: chatStore),
),
],
),
if (chatStore.settings.showBottomBar) ChatBottomBar(chatStore: chatStore),
if (chatStore.assetsStore.showEmoteMenu)
SizedBox(
height: MediaQuery.of(context).size.height / 3,
child: EmoteMenu(chatStore: chatStore),
),
],
);
},
);
}
}

View file

@ -71,7 +71,7 @@ class _ChattersListState extends State<ChattersList> {
onChanged: (text) => chatDetailStore.filterText = text,
decoration: InputDecoration(
isDense: true,
hintText: 'Filter',
labelText: 'Filter',
contentPadding: const EdgeInsets.all(10.0),
suffixIcon: IconButton(
tooltip: 'Clear Filter',

View file

@ -95,7 +95,7 @@ class ChatBottomBar extends StatelessWidget {
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(15.0)),
),
hintText: chatStore.auth.isLoggedIn ? 'Send a message' : 'Log in to chat',
labelText: chatStore.auth.isLoggedIn ? 'Send a message' : 'Log in to chat',
),
controller: chatStore.textController,
onSubmitted: chatStore.sendMessage,

View file

@ -90,24 +90,6 @@ abstract class _ChatStoreBase with Store {
required this.channelId,
required this.displayName,
}) {
// Create a reaction where anytime the emote menu is shown or hidden,
// scroll to the bottom of the list. This will prevent the emote menu
// from covering the latest messages when summoned.
reactions.add(reaction(
(_) => assetsStore.showEmoteMenu,
(_) => SchedulerBinding.instance?.addPostFrameCallback((_) {
if (scrollController.hasClients) scrollController.jumpTo(scrollController.position.maxScrollExtent);
}),
));
// Create a reaction for scrolling to bottom when exiting fullscreen.
reactions.add(reaction(
(_) => settings.fullScreen,
(_) => SchedulerBinding.instance?.addPostFrameCallback((_) {
if (scrollController.hasClients) scrollController.jumpTo(scrollController.position.maxScrollExtent);
}),
));
// Create a reaction that will reconnect to chat when logging in or out.
// Closing the channel will trigger a reconnect with the new credentials.
reactions.add(reaction(
@ -132,18 +114,9 @@ abstract class _ChatStoreBase with Store {
}
});
// Add a listener to the textfield focus that will do the following when focused:
// 1. Hide the emote menu if it is currently shown
// 2. Scroll to the latest message (after a brief delay)
// Add a listener to the textfield focus that will hide the emote menu if it is currently shown.
textFieldFocusNode.addListener(() {
if (textFieldFocusNode.hasFocus) {
if (assetsStore.showEmoteMenu) assetsStore.showEmoteMenu = false;
Future.delayed(
const Duration(milliseconds: 500),
() => scrollController.jumpTo(scrollController.position.maxScrollExtent),
);
}
if (textFieldFocusNode.hasFocus && assetsStore.showEmoteMenu) assetsStore.showEmoteMenu = false;
});
// Add a listener to the textfield that will show/hide the autocomplete bar if focused.
@ -327,29 +300,33 @@ abstract class _ChatStoreBase with Store {
if (_channel == null || _channel?.closeCode != null) {
_messages.add(IRCMessage.createNotice(message: 'Failed to send message: disconnected from chat.'));
return;
}
} else {
// Send the message to the IRC chat room.
_channel?.sink.add('PRIVMSG #$channelName :$message');
// Send the message to the IRC chat room.
_channel?.sink.add('PRIVMSG #$channelName :$message');
// Obtain the logged-in user's appearance in chat with USERSTATE and create the full message to render.
var userStateString = _userState.raw;
if (userStateString != null) {
if (message.length > 3 && message.substring(0, 3) == '/me') {
userStateString += ' :\x01ACTION ${message.replaceRange(0, 3, '').trim()}\x01';
} else {
userStateString += ' :' + message.trim();
}
// Obtain the logged-in user's appearance in chat with USERSTATE and create the full message to render.
var userStateString = _userState.raw;
if (userStateString != null) {
if (message.length > 3 && message.substring(0, 3) == '/me') {
userStateString += ' :\x01ACTION ${message.replaceRange(0, 3, '').trim()}\x01';
} else {
userStateString += ' :' + message.trim();
final userChatMessage = IRCMessage.fromString(userStateString);
userChatMessage.localEmotes?.addAll(assetsStore.userEmoteToObject);
toSend = userChatMessage;
}
final userChatMessage = IRCMessage.fromString(userStateString);
userChatMessage.localEmotes?.addAll(assetsStore.userEmoteToObject);
toSend = userChatMessage;
// Clear the previous input in the TextField.
textController.clear();
}
// Clear the previous input in the TextField.
textController.clear();
// Scroll to the latest message after sending.
SchedulerBinding.instance?.addPostFrameCallback((_) {
if (scrollController.hasClients) scrollController.jumpTo(scrollController.position.maxScrollExtent);
});
}
/// Adds the given [emote] to the chat textfield.

View file

@ -4,21 +4,17 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:frosty/constants/constants.dart';
import 'package:frosty/main.dart';
import 'package:frosty/screens/channel/stores/video_store.dart';
import 'package:frosty/screens/settings/settings.dart';
import 'package:intl/intl.dart';
class VideoOverlay extends StatefulWidget {
class VideoOverlay extends StatelessWidget {
final VideoStore videoStore;
const VideoOverlay({Key? key, required this.videoStore}) : super(key: key);
@override
State<VideoOverlay> createState() => _VideoOverlayState();
}
class _VideoOverlayState extends State<VideoOverlay> {
Future<void> _showSleepTimerDialog(BuildContext oldContext) {
Future<void> _showSleepTimerDialog(BuildContext context) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
@ -30,9 +26,9 @@ class _VideoOverlayState extends State<VideoOverlay> {
Row(
children: [
DropdownButton(
value: widget.videoStore.sleepHours,
value: videoStore.sleepHours,
items: List.generate(24, (index) => index).map((e) => DropdownMenuItem(value: e, child: Text(e.toString()))).toList(),
onChanged: (int? hours) => widget.videoStore.sleepHours = hours!,
onChanged: (int? hours) => videoStore.sleepHours = hours!,
menuMaxHeight: 200,
),
const SizedBox(width: 10.0),
@ -42,24 +38,24 @@ class _VideoOverlayState extends State<VideoOverlay> {
Row(
children: [
DropdownButton(
value: widget.videoStore.sleepMinutes,
value: videoStore.sleepMinutes,
items: List.generate(60, (index) => index).map((e) => DropdownMenuItem(value: e, child: Text(e.toString()))).toList(),
onChanged: (int? minutes) => widget.videoStore.sleepMinutes = minutes!,
onChanged: (int? minutes) => videoStore.sleepMinutes = minutes!,
menuMaxHeight: 200,
),
const SizedBox(width: 10.0),
const Text('Minutes'),
],
),
if (widget.videoStore.sleepTimer != null && widget.videoStore.sleepTimer!.isActive)
if (videoStore.sleepTimer != null && videoStore.sleepTimer!.isActive)
Row(
children: [
const Icon(Icons.timer),
Text(' ${widget.videoStore.timeRemaining.toString().split('.')[0]}'),
Text(' ${videoStore.timeRemaining.toString().split('.')[0]}'),
const Spacer(),
IconButton(
tooltip: 'Cancel Timer',
onPressed: widget.videoStore.cancelSleepTimer,
onPressed: videoStore.cancelSleepTimer,
icon: const Icon(Icons.cancel),
),
],
@ -75,13 +71,10 @@ class _VideoOverlayState extends State<VideoOverlay> {
),
Observer(
builder: (context) => ElevatedButton(
onPressed: widget.videoStore.sleepHours == 0 && widget.videoStore.sleepMinutes == 0
onPressed: videoStore.sleepHours == 0 && videoStore.sleepMinutes == 0
? null
: () => widget.videoStore.updateSleepTimer(
onTimerFinished: () => Navigator.popUntil(
oldContext,
(route) => route.isFirst,
),
: () => videoStore.updateSleepTimer(
onTimerFinished: () => navigatorKey.currentState?.popUntil((route) => route.isFirst),
),
child: const Text('Set Timer'),
),
@ -118,7 +111,7 @@ class _VideoOverlayState extends State<VideoOverlay> {
context: context,
builder: (context) => SizedBox(
height: MediaQuery.of(context).size.height * 0.8,
child: Settings(settingsStore: widget.videoStore.settingsStore),
child: Settings(settingsStore: videoStore.settingsStore),
),
),
);
@ -129,12 +122,12 @@ class _VideoOverlayState extends State<VideoOverlay> {
Icons.refresh,
color: Colors.white,
),
onPressed: widget.videoStore.handleRefresh,
onPressed: videoStore.handleRefresh,
);
final fullScreenButton = IconButton(
tooltip: widget.videoStore.settingsStore.fullScreen ? 'Exit Fullscreen' : 'Enter Fullscreen',
icon: widget.videoStore.settingsStore.fullScreen
tooltip: videoStore.settingsStore.fullScreen ? 'Exit Fullscreen' : 'Enter Fullscreen',
icon: videoStore.settingsStore.fullScreen
? const Icon(
Icons.fullscreen_exit,
color: Colors.white,
@ -143,7 +136,7 @@ class _VideoOverlayState extends State<VideoOverlay> {
Icons.fullscreen,
color: Colors.white,
),
onPressed: () => widget.videoStore.settingsStore.fullScreen = !widget.videoStore.settingsStore.fullScreen,
onPressed: () => videoStore.settingsStore.fullScreen = !videoStore.settingsStore.fullScreen,
);
final sleepTimerButton = IconButton(
@ -155,7 +148,7 @@ class _VideoOverlayState extends State<VideoOverlay> {
onPressed: () => _showSleepTimerDialog(context),
);
final streamInfo = widget.videoStore.streamInfo;
final streamInfo = videoStore.streamInfo;
if (streamInfo == null) {
return Stack(
@ -208,9 +201,9 @@ class _VideoOverlayState extends State<VideoOverlay> {
if (Platform.isAndroid)
Center(
child: IconButton(
tooltip: widget.videoStore.paused ? 'Play' : 'Pause',
tooltip: videoStore.paused ? 'Play' : 'Pause',
iconSize: 50.0,
icon: widget.videoStore.paused
icon: videoStore.paused
? const Icon(
Icons.play_arrow,
color: Colors.white,
@ -219,10 +212,10 @@ class _VideoOverlayState extends State<VideoOverlay> {
Icons.pause,
color: Colors.white,
),
onPressed: widget.videoStore.handlePausePlay,
onPressed: videoStore.handlePausePlay,
),
)
else if (!widget.videoStore.paused)
else if (!videoStore.paused)
Center(
child: IconButton(
tooltip: 'Pause',
@ -231,7 +224,7 @@ class _VideoOverlayState extends State<VideoOverlay> {
Icons.pause,
color: Colors.white,
),
onPressed: widget.videoStore.handlePausePlay,
onPressed: videoStore.handlePausePlay,
),
),
Align(
@ -241,10 +234,10 @@ class _VideoOverlayState extends State<VideoOverlay> {
children: [
Expanded(
child: GestureDetector(
onTap: widget.videoStore.handleExpand,
onTap: videoStore.handleExpand,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: widget.videoStore.settingsStore.expandInfo
child: videoStore.settingsStore.expandInfo
? Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
@ -252,11 +245,11 @@ class _VideoOverlayState extends State<VideoOverlay> {
streamer,
const SizedBox(height: 5.0),
Tooltip(
message: widget.videoStore.streamInfo!.title.trim(),
message: videoStore.streamInfo!.title.trim(),
preferBelow: false,
padding: const EdgeInsets.all(10.0),
child: Text(
widget.videoStore.streamInfo!.title.trim(),
videoStore.streamInfo!.title.trim(),
maxLines: orientation == Orientation.portrait ? 1 : 5,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
@ -267,7 +260,7 @@ class _VideoOverlayState extends State<VideoOverlay> {
),
const SizedBox(height: 5.0),
Text(
'${widget.videoStore.streamInfo?.gameName} \u2022 ${NumberFormat().format(widget.videoStore.streamInfo?.viewerCount)} viewers',
'${videoStore.streamInfo?.gameName} \u2022 ${NumberFormat().format(videoStore.streamInfo?.viewerCount)} viewers',
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w300,
@ -280,14 +273,14 @@ class _VideoOverlayState extends State<VideoOverlay> {
),
),
refreshButton,
if (Platform.isIOS && widget.videoStore.settingsStore.pictureInPicture)
if (Platform.isIOS && videoStore.settingsStore.pictureInPicture)
IconButton(
tooltip: 'Picture-in-Picture',
icon: const Icon(
Icons.picture_in_picture_alt_rounded,
color: Colors.white,
),
onPressed: widget.videoStore.requestPictureInPicture,
onPressed: videoStore.requestPictureInPicture,
),
if (orientation == Orientation.landscape) fullScreenButton
],
@ -297,10 +290,4 @@ class _VideoOverlayState extends State<VideoOverlay> {
),
);
}
@override
void dispose() {
widget.videoStore.cancelSleepTimer();
super.dispose();
}
}

View file

@ -146,12 +146,12 @@ class _VideoChatState extends State<VideoChat> {
return Scaffold(
body: OrientationBuilder(
builder: (context, orientation) {
if (orientation == Orientation.landscape) {
// Add a post-frame callback to scroll to bottom when rotating.
SchedulerBinding.instance?.addPostFrameCallback((_) {
if (_chatStore.scrollController.hasClients) _chatStore.scrollController.jumpTo(_chatStore.scrollController.position.maxScrollExtent);
});
// Scroll to bottom when summoning keyboard or rotating.
SchedulerBinding.instance?.addPostFrameCallback((_) {
if (_chatStore.scrollController.hasClients) _chatStore.scrollController.jumpTo(_chatStore.scrollController.position.maxScrollExtent);
});
if (orientation == Orientation.landscape) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
return Observer(
@ -228,6 +228,8 @@ class _VideoChatState extends State<VideoChat> {
void dispose() {
_chatStore.dispose();
_videoStore.cancelSleepTimer();
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.manual,
overlays: SystemUiOverlay.values,

View file

@ -37,7 +37,7 @@ class _SearchState extends State<Search> {
autocorrect: false,
decoration: InputDecoration(
isDense: true,
hintText: 'Find a channel or category',
labelText: 'Find a channel or category',
contentPadding: const EdgeInsets.all(10.0),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(15.0)),

View file

@ -124,7 +124,7 @@ class ProfileCard extends StatelessWidget {
child: TextField(
textAlign: TextAlign.center,
decoration: const InputDecoration(
hintText: 'Token',
labelText: 'Token',
),
onSubmitted: (token) {
authStore.login(customToken: token);

View file

@ -505,14 +505,14 @@ packages:
name: package_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.0"
version: "1.4.2"
package_info_plus_linux:
dependency: transitive
description:
name: package_info_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
version: "1.0.5"
package_info_plus_macos:
dependency: transitive
description:
@ -533,14 +533,14 @@ packages:
name: package_info_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
version: "1.0.5"
package_info_plus_windows:
dependency: transitive
description:
name: package_info_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
version: "1.0.5"
path:
dependency: transitive
description:
@ -979,14 +979,14 @@ packages:
name: webview_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "3.0.2"
webview_flutter_android:
dependency: transitive
description:
name: webview_flutter_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.4"
version: "2.8.5"
webview_flutter_platform_interface:
dependency: transitive
description:
@ -1000,7 +1000,7 @@ packages:
name: webview_flutter_wkwebview
url: "https://pub.dartlang.org"
source: hosted
version: "2.7.1"
version: "2.7.2"
win32:
dependency: transitive
description:

View file

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.2.1+19
version: 1.2.2+20
environment:
sdk: ">=2.15.0 <3.0.0"