diff --git a/lib/licenses.dart b/lib/licenses.dart index 36a9f577..a665eed0 100644 --- a/lib/licenses.dart +++ b/lib/licenses.dart @@ -115,6 +115,5 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.'''); - yield LicenseEntryWithLineBreaks(["flaticons"], "Icons made by Freepik (https://www.freepik.com) from Flaticon (www.flaticon.com)"); } diff --git a/lib/main.dart b/lib/main.dart index f74ddbdc..b59fe208 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -190,7 +190,8 @@ class FlwtchState extends State { }, ), ); - } else { //dual pane + } else { + //dual pane Provider.of(navKey.currentContext!, listen: false).selectedProfile = args["ProfileOnion"]; Provider.of(navKey.currentContext!, listen: false).selectedConversation = args["Handle"]; } diff --git a/lib/notification_manager.dart b/lib/notification_manager.dart index ea4e9a78..fa5de8c3 100644 --- a/lib/notification_manager.dart +++ b/lib/notification_manager.dart @@ -22,10 +22,7 @@ class LinuxNotificationsManager implements NotificationsManager { } Future notify(String message) async { var iconPath = Uri.file(path.join(path.current, "cwtch.png")); - client.notify(message, appName: "cwtch", - appIcon: iconPath.toString(), - replacesId: this.previous_id).then((Notification value) => - previous_id = value.id); + client.notify(message, appName: "cwtch", appIcon: iconPath.toString(), replacesId: this.previous_id).then((Notification value) => previous_id = value.id); } } @@ -40,4 +37,4 @@ NotificationsManager newDesktopNotificationsManager() { print("Attempted to access DBUS for notifications but failed. Switching off notifications."); } return NullNotificationsManager(); -} \ No newline at end of file +} diff --git a/lib/opaque.dart b/lib/opaque.dart index b6ba50bf..fa09fc41 100644 --- a/lib/opaque.dart +++ b/lib/opaque.dart @@ -314,7 +314,6 @@ abstract class OpaqueThemeType { double contactOnionTextSize() { return 18; } - } class OpaqueDark extends OpaqueThemeType { @@ -1440,4 +1439,4 @@ class Opaque extends OpaqueThemeType { } } -*/ \ No newline at end of file +*/ diff --git a/lib/settings.dart b/lib/settings.dart index d63333dc..843076ba 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -161,26 +161,40 @@ class Settings extends ChangeNotifier { List uiColumns(bool isLandscape) { var m = (!isLandscape || uiColumnModeLandscape == DualpaneMode.CopyPortrait) ? uiColumnModePortrait : uiColumnModeLandscape; - switch(m) { - case DualpaneMode.Single: return [1]; - case DualpaneMode.Dual1to2: return [1, 2]; - case DualpaneMode.Dual1to4: return [1, 4]; + switch (m) { + case DualpaneMode.Single: + return [1]; + case DualpaneMode.Dual1to2: + return [1, 2]; + case DualpaneMode.Dual1to4: + return [1, 4]; } print("impossible column configuration: portrait/$uiColumnModePortrait landscape/$uiColumnModeLandscape"); return [1]; } static List uiColumnModeOptions(bool isLandscape) { - if (isLandscape) return [DualpaneMode.CopyPortrait, DualpaneMode.Single, DualpaneMode.Dual1to2, DualpaneMode.Dual1to4,]; - else return [DualpaneMode.Single, DualpaneMode.Dual1to2, DualpaneMode.Dual1to4]; + if (isLandscape) + return [ + DualpaneMode.CopyPortrait, + DualpaneMode.Single, + DualpaneMode.Dual1to2, + DualpaneMode.Dual1to4, + ]; + else + return [DualpaneMode.Single, DualpaneMode.Dual1to2, DualpaneMode.Dual1to4]; } static DualpaneMode uiColumnModeFromString(String m) { - switch(m) { - case "DualpaneMode.Single": return DualpaneMode.Single; - case "DualpaneMode.Dual1to2": return DualpaneMode.Dual1to2; - case "DualpaneMode.Dual1to4": return DualpaneMode.Dual1to4; - case "DualpaneMode.CopyPortrait": return DualpaneMode.CopyPortrait; + switch (m) { + case "DualpaneMode.Single": + return DualpaneMode.Single; + case "DualpaneMode.Dual1to2": + return DualpaneMode.Dual1to2; + case "DualpaneMode.Dual1to4": + return DualpaneMode.Dual1to4; + case "DualpaneMode.CopyPortrait": + return DualpaneMode.CopyPortrait; } print("Error: ui requested translation of column mode [$m] which doesn't exist"); return DualpaneMode.Single; @@ -188,11 +202,15 @@ class Settings extends ChangeNotifier { static String uiColumnModeToString(DualpaneMode m) { // todo: translate - switch(m) { - case DualpaneMode.Single: return "Single"; - case DualpaneMode.Dual1to2: return "Double (1:2)"; - case DualpaneMode.Dual1to4: return "Double (1:4)"; - case DualpaneMode.CopyPortrait: return "Same as portrait mode setting"; + switch (m) { + case DualpaneMode.Single: + return "Single"; + case DualpaneMode.Dual1to2: + return "Double (1:2)"; + case DualpaneMode.Dual1to4: + return "Double (1:4)"; + case DualpaneMode.CopyPortrait: + return "Same as portrait mode setting"; } } diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index 93a10ccb..26d2dcd7 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -166,7 +166,10 @@ class _AddEditProfileViewState extends State { autoFillHints: [AutofillHints.newPassword], validator: (value) { // Password field can be empty when just updating the profile, not on creation - if (Provider.of(context).isEncrypted && Provider.of(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) { + if (Provider.of(context).isEncrypted && + Provider.of(context, listen: false).onion.isEmpty && + value.isEmpty && + usePassword) { return AppLocalizations.of(context)!.passwordErrorEmpty; } if (Provider.of(context).deleteProfileError == true) { diff --git a/lib/views/doublecolview.dart b/lib/views/doublecolview.dart index 2737755e..e7d3a260 100644 --- a/lib/views/doublecolview.dart +++ b/lib/views/doublecolview.dart @@ -29,7 +29,7 @@ class _DoubleColumnViewState extends State { Flexible( flex: cols[1], child: flwtch.selectedConversation == null - ? Card(child:Center(child: Text(AppLocalizations.of(context)!.addContactFirst))) + ? Card(child: Center(child: Text(AppLocalizations.of(context)!.addContactFirst))) : //dev MultiProvider(providers: [ ChangeNotifierProvider.value(value: Provider.of(context)), diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 2329ea83..310db952 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -169,7 +169,7 @@ class _GlobalSettingsViewState extends State { )), AboutListTile( icon: Icon(Icons.info, color: settings.current().mainTextColor()), - applicationIcon: Padding(padding:EdgeInsets.all(5), child: Icon(CwtchIcons.cwtch_knott)), + applicationIcon: Padding(padding: EdgeInsets.all(5), child: Icon(CwtchIcons.cwtch_knott)), applicationName: "Cwtch (Flutter UI)", applicationVersion: AppLocalizations.of(context)!.versionBuilddate.replaceAll("%1", EnvironmentConfig.BUILD_VER).replaceAll("%2", EnvironmentConfig.BUILD_DATE), applicationLegalese: '\u{a9} 2021 Open Privacy Research Society', diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index da13f2c1..bdba1c9f 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -50,17 +50,19 @@ class _MessageViewState extends State { appBar: AppBar( // setting leading to null makes it do the default behaviour; container() hides it leading: Provider.of(context).uiColumns(appState.isLandscape(context)).length > 1 ? Container() : null, - title: Row(children: [ - ProfileImage( - imagePath: Provider.of(context).imagePath, - diameter: 42, - border: Provider.of(context).current().portraitOnlineBorderColor(), - badgeTextColor: Colors.red, - badgeColor: Colors.red, - ), - SizedBox( - width: 10, - ),Text(Provider.of(context).nickname)]), + title: Row(children: [ + ProfileImage( + imagePath: Provider.of(context).imagePath, + diameter: 42, + border: Provider.of(context).current().portraitOnlineBorderColor(), + badgeTextColor: Colors.red, + badgeColor: Colors.red, + ), + SizedBox( + width: 10, + ), + Text(Provider.of(context).nickname) + ]), actions: [ //IconButton(icon: Icon(Icons.chat), onPressed: _pushContactSettings), //IconButton(icon: Icon(Icons.list), onPressed: _pushContactSettings), diff --git a/lib/views/profilemgrview.dart b/lib/views/profilemgrview.dart index 2e65a2f8..80a037f4 100644 --- a/lib/views/profilemgrview.dart +++ b/lib/views/profilemgrview.dart @@ -40,45 +40,41 @@ class _ProfileMgrViewState extends State { // Prevents Android back button from closing the app on the profile manager screen // (which would shutdown connections and all kinds of other expensive to generate things) // TODO pop up a dialogue regarding closing the app? - builder: (context, settings, child) => - WillPopScope( - onWillPop: () async { - _modalShutdown(); - return Provider.of(context, listen: false).cwtchIsClosing; - }, - child: Scaffold( - backgroundColor: settings.theme.backgroundMainColor(), - appBar: AppBar( - title: Row(children: [ - Image( - image: AssetImage("assets/core/knott-white.png"), - filterQuality: FilterQuality.medium, - isAntiAlias: true, - width: 32, - height: 32, - colorBlendMode: BlendMode.dstIn, - color: Provider - .of(context) - .theme - .backgroundHilightElementColor(), - ), - SizedBox( - width: 10, - ), - Expanded(child: Text(AppLocalizations.of(context)!.titleManageProfiles, style: TextStyle(color: settings.current().mainTextColor()))) - ]), - actions: getActions(), + builder: (context, settings, child) => WillPopScope( + onWillPop: () async { + _modalShutdown(); + return Provider.of(context, listen: false).cwtchIsClosing; + }, + child: Scaffold( + backgroundColor: settings.theme.backgroundMainColor(), + appBar: AppBar( + title: Row(children: [ + Image( + image: AssetImage("assets/core/knott-white.png"), + filterQuality: FilterQuality.medium, + isAntiAlias: true, + width: 32, + height: 32, + colorBlendMode: BlendMode.dstIn, + color: Provider.of(context).theme.backgroundHilightElementColor(), ), - floatingActionButton: FloatingActionButton( - onPressed: _pushAddEditProfile, - tooltip: AppLocalizations.of(context)!.addNewProfileBtn, - child: Icon( - Icons.add, - semanticLabel: AppLocalizations.of(context)!.addNewProfileBtn, - ), + SizedBox( + width: 10, ), - body: _buildProfileManager(), - )), + Expanded(child: Text(AppLocalizations.of(context)!.titleManageProfiles, style: TextStyle(color: settings.current().mainTextColor()))) + ]), + actions: getActions(), + ), + floatingActionButton: FloatingActionButton( + onPressed: _pushAddEditProfile, + tooltip: AppLocalizations.of(context)!.addNewProfileBtn, + child: Icon( + Icons.add, + semanticLabel: AppLocalizations.of(context)!.addNewProfileBtn, + ), + ), + body: _buildProfileManager(), + )), ); } diff --git a/lib/widgets/contactrow.dart b/lib/widgets/contactrow.dart index 296ae406..d38d1df1 100644 --- a/lib/widgets/contactrow.dart +++ b/lib/widgets/contactrow.dart @@ -33,7 +33,11 @@ class _ContactRowState extends State { diameter: 64.0, imagePath: contact.imagePath, maskOut: !contact.isOnline(), - border: contact.isOnline() ? Provider.of(context).theme.portraitOnlineBorderColor() : contact.isBlocked ? Provider.of(context).theme.portraitBlockedBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), + border: contact.isOnline() + ? Provider.of(context).theme.portraitOnlineBorderColor() + : contact.isBlocked + ? Provider.of(context).theme.portraitBlockedBorderColor() + : Provider.of(context).theme.portraitOfflineBorderColor()), ), Expanded( child: Padding( @@ -44,13 +48,16 @@ class _ContactRowState extends State { Text( contact.nickname, //(contact.isInvitation ? "invite " : "non-invite ") + (contact.isBlocked ? "blokt" : "nonblokt"),// - style: TextStyle(fontSize: Provider.of(context).theme.contactOnionTextSize(), - color: contact.isBlocked ? Provider.of(context).theme.portraitBlockedTextColor() : Provider.of(context).theme.mainTextColor()), //Provider.of(context).biggerFont, + style: TextStyle( + fontSize: Provider.of(context).theme.contactOnionTextSize(), + color: contact.isBlocked + ? Provider.of(context).theme.portraitBlockedTextColor() + : Provider.of(context).theme.mainTextColor()), //Provider.of(context).biggerFont, softWrap: true, overflow: TextOverflow.visible, ), Text(contact.onion, - style: TextStyle(color: contact.isBlocked ? Provider.of(context).theme.portraitBlockedTextColor() : Provider.of(context).theme.mainTextColor())), + style: TextStyle(color: contact.isBlocked ? Provider.of(context).theme.portraitBlockedTextColor() : Provider.of(context).theme.mainTextColor())), ], ))), Padding( @@ -60,7 +67,10 @@ class _ContactRowState extends State { IconButton( padding: EdgeInsets.zero, iconSize: 16, - icon: Icon(Icons.favorite, color: Provider.of(context).theme.mainTextColor(),), + icon: Icon( + Icons.favorite, + color: Provider.of(context).theme.mainTextColor(), + ), tooltip: AppLocalizations.of(context)!.tooltipAcceptContactRequest, onPressed: _btnApprove, ), diff --git a/lib/widgets/invitationbubble.dart b/lib/widgets/invitationbubble.dart index ff86ffca..47057f74 100644 --- a/lib/widgets/invitationbubble.dart +++ b/lib/widgets/invitationbubble.dart @@ -66,18 +66,18 @@ class InvitationBubbleState extends State { return MalformedBubble(); } - var wdgMessage = isGroup && !showGroupInvite ? - Text(AppLocalizations.of(context)!.groupInviteSettingsWarning) : - fromMe - ? senderInviteChrome(AppLocalizations.of(context)!.sendAnInvitation, - isGroup ? Provider.of(context).contactList.getContact(Provider.of(context).inviteTarget)!.nickname : Provider.of(context).message, myKey) - : (inviteChrome(isGroup ? AppLocalizations.of(context)!.inviteToGroup : AppLocalizations.of(context)!.contactSuggestion, Provider.of(context).inviteNick, - Provider.of(context).inviteTarget, myKey)); + var wdgMessage = isGroup && !showGroupInvite + ? Text(AppLocalizations.of(context)!.groupInviteSettingsWarning) + : fromMe + ? senderInviteChrome(AppLocalizations.of(context)!.sendAnInvitation, + isGroup ? Provider.of(context).contactList.getContact(Provider.of(context).inviteTarget)!.nickname : Provider.of(context).message, myKey) + : (inviteChrome(isGroup ? AppLocalizations.of(context)!.inviteToGroup : AppLocalizations.of(context)!.contactSuggestion, Provider.of(context).inviteNick, + Provider.of(context).inviteTarget, myKey)); Widget wdgDecorations; if (isGroup && !showGroupInvite) { wdgDecorations = Text('\u202F'); - } else if (fromMe) { + } else if (fromMe) { wdgDecorations = MessageBubbleDecoration(ackd: Provider.of(context).ackd, errored: Provider.of(context).error, fromMe: fromMe, prettyDate: prettyDate); } else if (isAccepted) { wdgDecorations = Text(AppLocalizations.of(context)!.accepted + '\u202F'); @@ -113,7 +113,8 @@ class InvitationBubbleState extends State { child: Padding( padding: EdgeInsets.all(9.0), child: Wrap(runAlignment: WrapAlignment.spaceEvenly, alignment: WrapAlignment.spaceEvenly, runSpacing: 1.0, crossAxisAlignment: WrapCrossAlignment.center, children: [ - Center(widthFactor: 1, child: Padding(padding: EdgeInsets.all(10.0), child: Icon(isGroup && !showGroupInvite ? CwtchIcons.enable_experiments : CwtchIcons.send_invite, size: 32))), + Center( + widthFactor: 1, child: Padding(padding: EdgeInsets.all(10.0), child: Icon(isGroup && !showGroupInvite ? CwtchIcons.enable_experiments : CwtchIcons.send_invite, size: 32))), Center( widthFactor: 1.0, child: Column( diff --git a/lib/widgets/messagelist.dart b/lib/widgets/messagelist.dart index b17b7bbf..5e985b7d 100644 --- a/lib/widgets/messagelist.dart +++ b/lib/widgets/messagelist.dart @@ -16,11 +16,10 @@ class _MessageListState extends State { @override Widget build(BuildContext outerContext) { - - bool isP2P = !Provider.of(context).isGroup; + bool isP2P = !Provider.of(context).isGroup; bool isGroupAndSyncing = Provider.of(context).isGroup == true && Provider.of(context).status == "Authenticated"; bool isGroupAndSynced = Provider.of(context).isGroup && Provider.of(context).status == "Synced"; - bool isGroupAndNotAuthenticated= Provider.of(context).isGroup && Provider.of(context).status != "Authenticated"; + bool isGroupAndNotAuthenticated = Provider.of(context).isGroup && Provider.of(context).status != "Authenticated"; bool showEphemeralWarning = (isP2P && Provider.of(context).savePeerHistory != "SaveHistory"); bool showOfflineWarning = Provider.of(context).isOnline() == false; @@ -37,18 +36,17 @@ class _MessageListState extends State { child: Container( padding: EdgeInsets.all(5.0), color: Provider.of(context).theme.defaultButtonActiveColor(), - child: showSyncing ? - Text(AppLocalizations.of(context)!.serverNotSynced, - textAlign: TextAlign.center) - : showOfflineWarning - ? Text(Provider.of(context).isGroup ? AppLocalizations.of(context)!.serverConnectivityDisconnected : AppLocalizations.of(context)!.peerOfflineMessage, - textAlign: TextAlign.center) - // Only show the ephemeral status for peer conversations, not for groups... - : (showEphemeralWarning - ? Text(AppLocalizations.of(context)!.chatHistoryDefault, textAlign: TextAlign.center) - : - // We are not allowed to put null here, so put an empty text widge - Text("")), + child: showSyncing + ? Text(AppLocalizations.of(context)!.serverNotSynced, textAlign: TextAlign.center) + : showOfflineWarning + ? Text(Provider.of(context).isGroup ? AppLocalizations.of(context)!.serverConnectivityDisconnected : AppLocalizations.of(context)!.peerOfflineMessage, + textAlign: TextAlign.center) + // Only show the ephemeral status for peer conversations, not for groups... + : (showEphemeralWarning + ? Text(AppLocalizations.of(context)!.chatHistoryDefault, textAlign: TextAlign.center) + : + // We are not allowed to put null here, so put an empty text widge + Text("")), )), Expanded( child: Scrollbar( @@ -63,30 +61,32 @@ class _MessageListState extends State { alignment: Alignment.center, image: AssetImage("assets/core/negative_heart_512px.png"), colorFilter: ColorFilter.mode(Provider.of(context).theme.hilightElementTextColor(), BlendMode.srcIn))), - // Don't load messages for syncing server... - child: loadMessages ? ListView.builder( - controller: ctrlr1, - itemCount: Provider.of(outerContext).totalMessages, - reverse: true, // NOTE: There seems to be a bug in flutter that corrects the mouse wheel scroll, but not the drag direction... - itemBuilder: (itemBuilderContext, index) { - var trueIndex = Provider.of(outerContext).totalMessages - index - 1; - return ChangeNotifierProvider( - key: ValueKey(trueIndex), - create: (x) => MessageState( - context: itemBuilderContext, - profileOnion: Provider.of(outerContext, listen: false).onion, - // We don't want to listen for updates to the contact handle... - contactHandle: Provider.of(x, listen: false).onion, - messageIndex: trueIndex, - ), - builder: (bcontext, child) { - String idx = Provider.of(outerContext).isGroup == true && Provider.of(bcontext).signature.isEmpty == false - ? Provider.of(bcontext).signature - : trueIndex.toString(); - return RepaintBoundary(child: MessageRow(key: Provider.of(bcontext).getMessageKey(idx))); - }); - }, - ) : null ))) + // Don't load messages for syncing server... + child: loadMessages + ? ListView.builder( + controller: ctrlr1, + itemCount: Provider.of(outerContext).totalMessages, + reverse: true, // NOTE: There seems to be a bug in flutter that corrects the mouse wheel scroll, but not the drag direction... + itemBuilder: (itemBuilderContext, index) { + var trueIndex = Provider.of(outerContext).totalMessages - index - 1; + return ChangeNotifierProvider( + key: ValueKey(trueIndex), + create: (x) => MessageState( + context: itemBuilderContext, + profileOnion: Provider.of(outerContext, listen: false).onion, + // We don't want to listen for updates to the contact handle... + contactHandle: Provider.of(x, listen: false).onion, + messageIndex: trueIndex, + ), + builder: (bcontext, child) { + String idx = Provider.of(outerContext).isGroup == true && Provider.of(bcontext).signature.isEmpty == false + ? Provider.of(bcontext).signature + : trueIndex.toString(); + return RepaintBoundary(child: MessageRow(key: Provider.of(bcontext).getMessageKey(idx))); + }); + }, + ) + : null))) ]))); } } diff --git a/lib/widgets/profilerow.dart b/lib/widgets/profilerow.dart index dfa79f69..de865c8e 100644 --- a/lib/widgets/profilerow.dart +++ b/lib/widgets/profilerow.dart @@ -30,43 +30,29 @@ class _ProfileRowState extends State { padding: const EdgeInsets.all(2.0), //border size child: ProfileImage( badgeCount: 0, - badgeColor: Provider - .of(context) - .theme - .portraitProfileBadgeColor(), - badgeTextColor: Provider - .of(context) - .theme - .portraitProfileBadgeTextColor(), + badgeColor: Provider.of(context).theme.portraitProfileBadgeColor(), + badgeTextColor: Provider.of(context).theme.portraitProfileBadgeTextColor(), diameter: 64.0, imagePath: profile.imagePath, - border: profile.isOnline ? Provider - .of(context) - .theme - .portraitOnlineBorderColor() : Provider - .of(context) - .theme - .portraitOfflineBorderColor())), + border: profile.isOnline ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor())), Expanded( child: Column( - children: [ - Text( - profile.nickname, - semanticsLabel: profile.nickname, - style: Provider - .of(context) - .biggerFont, - softWrap: true, - overflow: TextOverflow.ellipsis, - ), - ExcludeSemantics( - child: Text( - profile.onion, - softWrap: true, - overflow: TextOverflow.ellipsis, - )) - ], - )), + children: [ + Text( + profile.nickname, + semanticsLabel: profile.nickname, + style: Provider.of(context).biggerFont, + softWrap: true, + overflow: TextOverflow.ellipsis, + ), + ExcludeSemantics( + child: Text( + profile.onion, + softWrap: true, + overflow: TextOverflow.ellipsis, + )) + ], + )), IconButton( enableFeedback: true, tooltip: AppLocalizations.of(context)!.editProfile + " " + profile.nickname, @@ -83,7 +69,7 @@ class _ProfileRowState extends State { appState.selectedProfile = profile.onion; appState.selectedConversation = null; - _pushContactList(profile, appState.isLandscape(context));//orientation == Orientation.landscape); + _pushContactList(profile, appState.isLandscape(context)); //orientation == Orientation.landscape); }); }, )); @@ -94,19 +80,17 @@ class _ProfileRowState extends State { MaterialPageRoute( settings: RouteSettings(name: "conversations"), builder: (BuildContext buildcontext) { - return OrientationBuilder( - builder: (orientationBuilderContext, orientation) { - return MultiProvider( - providers: [ - ChangeNotifierProvider.value(value: profile), - ChangeNotifierProvider.value(value: profile.contactList), - ], - builder: (innercontext, widget) { - var appState = Provider.of(context); - var settings = Provider.of(context); - return settings.uiColumns(appState.isLandscape(innercontext)).length > 1 ? DoubleColumnView() : ContactsView(); - } - ); + return OrientationBuilder(builder: (orientationBuilderContext, orientation) { + return MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: profile), + ChangeNotifierProvider.value(value: profile.contactList), + ], + builder: (innercontext, widget) { + var appState = Provider.of(context); + var settings = Provider.of(context); + return settings.uiColumns(appState.isLandscape(innercontext)).length > 1 ? DoubleColumnView() : ContactsView(); + }); }); }, ),