made app cupertino compatible; improvements; bugfixes

This commit is contained in:
Myzel394 2022-08-17 19:57:55 +02:00
parent cee08c080f
commit 0b0c2ce15f
24 changed files with 696 additions and 365 deletions

View File

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"

View File

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"

View File

@ -13,6 +13,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
F2449A063F9DD54E63262023 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D38127B4F5788EF3381B2B4C /* Pods_Runner.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@ -32,9 +33,11 @@
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 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>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
6B64EB075DA14AE8EEB89C89 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
8B5ED7BEA3FBEF103E66F847 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; 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>"; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -42,6 +45,8 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D3486A5CDDD946E1FF3C0592 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
D38127B4F5788EF3381B2B4C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -49,12 +54,24 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
F2449A063F9DD54E63262023 /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
928A05FA6D1D23BECAA39FAE /* Pods */ = {
isa = PBXGroup;
children = (
6B64EB075DA14AE8EEB89C89 /* Pods-Runner.debug.xcconfig */,
8B5ED7BEA3FBEF103E66F847 /* Pods-Runner.release.xcconfig */,
D3486A5CDDD946E1FF3C0592 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = { 9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -72,6 +89,8 @@
9740EEB11CF90186004384FC /* Flutter */, 9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
928A05FA6D1D23BECAA39FAE /* Pods */,
A5CF9B62B23D4F71C0785FAA /* Frameworks */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@ -98,6 +117,14 @@
path = Runner; path = Runner;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
A5CF9B62B23D4F71C0785FAA /* Frameworks */ = {
isa = PBXGroup;
children = (
D38127B4F5788EF3381B2B4C /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@ -105,12 +132,14 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
6BF4497D0DD8B6C4E3A61453 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */, 9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */, 97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
8C74D292913673DDB09B3D1F /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
@ -183,6 +212,45 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
}; };
6BF4497D0DD8B6C4E3A61453 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
8C74D292913673DDB09B3D1F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -272,7 +340,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 15.5;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@ -288,6 +356,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 6FJFK7645A;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
@ -349,7 +418,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 15.5;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -398,7 +467,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 15.5;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@ -416,6 +485,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 6FJFK7645A;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
@ -438,6 +508,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 6FJFK7645A;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (

View File

@ -4,4 +4,7 @@
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace> </Workspace>

View File

@ -1,6 +1,7 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
final LIGHT_THEME = ThemeData( final LIGHT_THEME_MATERIAL = ThemeData(
textTheme: ThemeData().textTheme.copyWith( textTheme: ThemeData().textTheme.copyWith(
headline1: const TextStyle( headline1: const TextStyle(
fontSize: 32, fontSize: 32,
@ -17,7 +18,7 @@ final LIGHT_THEME = ThemeData(
), ),
); );
final DARK_THEME = ThemeData.dark().copyWith( final DARK_THEME_MATERIAL = ThemeData.dark().copyWith(
textTheme: ThemeData.dark().textTheme.copyWith( textTheme: ThemeData.dark().textTheme.copyWith(
headline1: const TextStyle( headline1: const TextStyle(
fontSize: 32, fontSize: 32,
@ -33,3 +34,12 @@ final DARK_THEME = ThemeData.dark().copyWith(
), ),
), ),
); );
final LIGHT_THEME_CUPERTINO = CupertinoThemeData().copyWith(
textTheme: CupertinoThemeData().textTheme.copyWith(
navLargeTitleTextStyle: const TextStyle(
fontSize: 32,
fontWeight: FontWeight.w500,
),
),
);

View File

@ -1,8 +1,8 @@
import 'package:camera/camera.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:quid_faciam_hodie/constants/themes.dart'; import 'package:quid_faciam_hodie/constants/themes.dart';
import 'package:quid_faciam_hodie/screens/calendar_screen.dart'; import 'package:quid_faciam_hodie/screens/calendar_screen.dart';
@ -24,7 +24,6 @@ void main() async {
DeviceOrientation.portraitDown, DeviceOrientation.portraitDown,
]); ]);
GlobalValuesManager.setCameras(await availableCameras());
GlobalValuesManager.initializeServer(); GlobalValuesManager.initializeServer();
runApp(const MyApp()); runApp(const MyApp());
@ -46,11 +45,16 @@ class _MyAppState extends State<MyApp> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ChangeNotifierProvider.value( return ChangeNotifierProvider.value(
value: memories, value: memories,
child: MaterialApp( child: PlatformApp(
title: 'Quid faciam hodie?', title: 'Quid faciam hodie?',
theme: LIGHT_THEME, material: (_, __) => MaterialAppData(
darkTheme: DARK_THEME, theme: LIGHT_THEME_MATERIAL,
darkTheme: DARK_THEME_MATERIAL,
themeMode: ThemeMode.system, themeMode: ThemeMode.system,
),
cupertino: (_, __) => CupertinoAppData(
theme: LIGHT_THEME_CUPERTINO,
),
localizationsDelegates: AppLocalizations.localizationsDelegates, localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales, supportedLocales: AppLocalizations.supportedLocales,
routes: { routes: {

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:flutter_sticky_header/flutter_sticky_header.dart'; import 'package:flutter_sticky_header/flutter_sticky_header.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart';
@ -9,7 +10,7 @@ import 'calendar_screen/calendar_month.dart';
import 'calendar_screen/days_of_week_strip.dart'; import 'calendar_screen/days_of_week_strip.dart';
class CalendarScreen extends StatelessWidget { class CalendarScreen extends StatelessWidget {
static const ID = 'calendar'; static const ID = '/calendar';
const CalendarScreen({ const CalendarScreen({
Key? key, Key? key,
@ -18,21 +19,31 @@ class CalendarScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final memoriesManager = context.read<Memories>(); final memoriesManager = context.read<Memories>();
final theme = Theme.of(context);
final calendarManager = CalendarManager(memories: memoriesManager.memories); final calendarManager = CalendarManager(memories: memoriesManager.memories);
final monthMapping = calendarManager.getMappingForList(); final monthMapping = calendarManager.getMappingForList();
return Consumer<Memories>( return Consumer<Memories>(
builder: (context, memories, _) => Scaffold( builder: (context, memories, _) => PlatformScaffold(
appBar: isCupertino(context)
? PlatformAppBar(
title: Text('Calendar'),
)
: null,
body: Padding( body: Padding(
padding: const EdgeInsets.symmetric(vertical: MEDIUM_SPACE), padding: EdgeInsets.only(
top: isCupertino(context) ? HUGE_SPACE : MEDIUM_SPACE,
),
child: CustomScrollView( child: CustomScrollView(
reverse: true, reverse: true,
slivers: [ slivers: [
SliverStickyHeader( SliverStickyHeader(
header: Container( header: Container(
color: theme.canvasColor, color: platformThemeData(
context,
material: (data) => data.canvasColor,
cupertino: (data) => data.barBackgroundColor,
),
padding: const EdgeInsets.symmetric(vertical: SMALL_SPACE), padding: const EdgeInsets.symmetric(vertical: SMALL_SPACE),
child: const DaysOfWeekStrip(), child: const DaysOfWeekStrip(),
), ),

View File

@ -2,6 +2,7 @@ import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_calendar_widget/flutter_calendar_widget.dart'; import 'package:flutter_calendar_widget/flutter_calendar_widget.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/constants/values.dart'; import 'package:quid_faciam_hodie/constants/values.dart';
@ -119,8 +120,6 @@ class CalendarMonth extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context);
return FlutterCalendar( return FlutterCalendar(
focusedDate: firstDate, focusedDate: firstDate,
selectionMode: CalendarSelectionMode.single, selectionMode: CalendarSelectionMode.single,
@ -157,13 +156,28 @@ class CalendarMonth extends StatelessWidget {
calenderMargin: EdgeInsets.symmetric(vertical: MEDIUM_SPACE), calenderMargin: EdgeInsets.symmetric(vertical: MEDIUM_SPACE),
), ),
textStyle: CalendarTextStyle( textStyle: CalendarTextStyle(
headerTextStyle: theme.textTheme.subtitle1!, headerTextStyle: platformThemeData(
dayOfWeekTextColor: theme.textTheme.bodyText2!.color!, context,
dayTextColor: theme.textTheme.bodyText1!.color!, material: (data) => data.textTheme.subtitle1!,
cupertino: (data) => data.textTheme.navTitleTextStyle,
),
dayTextColor: platformThemeData(
context,
material: (data) => data.textTheme.bodyText1!.color!,
cupertino: (data) => data.textTheme.textStyle.color!,
),
// Background color // Background color
selectedDayTextColor: theme.textTheme.bodyText1!.color!, selectedDayTextColor: platformThemeData(
context,
material: (data) => data.textTheme.bodyText1!.color!,
cupertino: (data) => data.textTheme.textStyle.color!,
),
// Foreground color // Foreground color
focusedDayTextColor: theme.dialogBackgroundColor, focusedDayTextColor: platformThemeData(
context,
material: (data) => data.dialogBackgroundColor,
cupertino: (data) => data.barBackgroundColor,
),
), ),
); );
} }

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_calendar_widget/flutter_calendar_widget.dart'; import 'package:flutter_calendar_widget/flutter_calendar_widget.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
class DaysOfWeekStrip extends StatelessWidget { class DaysOfWeekStrip extends StatelessWidget {
@ -20,8 +21,7 @@ class DaysOfWeekStrip extends StatelessWidget {
TableRow( TableRow(
children: List.generate( children: List.generate(
7, 7,
(index) => Container( (index) => Align(
child: Align(
child: Text( child: Text(
DateFormat.E().format( DateFormat.E().format(
DateTime(1900, 1, 1) DateTime(1900, 1, 1)
@ -34,6 +34,10 @@ class DaysOfWeekStrip extends StatelessWidget {
), ),
), ),
), ),
style: platformThemeData(
context,
material: (data) => data.textTheme.bodyText1!,
cupertino: (data) => data.textTheme.textStyle,
), ),
), ),
), ),

View File

@ -1,11 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/screens/main_screen.dart'; import 'package:quid_faciam_hodie/screens/main_screen.dart';
import 'grant_permission_screen/permissions_required_page.dart'; import 'grant_permission_screen/permissions_required_page.dart';
class GrantPermissionScreen extends StatelessWidget { class GrantPermissionScreen extends StatelessWidget {
static const ID = 'grant_permission'; static const ID = '/grant_permission';
const GrantPermissionScreen({Key? key}) : super(key: key); const GrantPermissionScreen({Key? key}) : super(key: key);
@ -13,17 +15,20 @@ class GrantPermissionScreen extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!; final localizations = AppLocalizations.of(context)!;
return Scaffold( return PlatformScaffold(
appBar: AppBar( appBar: PlatformAppBar(
title: Text(localizations.grantPermissionScreenTitle), title: Text(localizations.grantPermissionScreenTitle),
), ),
body: Center( body: Padding(
padding: const EdgeInsets.all(MEDIUM_SPACE),
child: Center(
child: PermissionsRequiredPage( child: PermissionsRequiredPage(
onPermissionsGranted: () { onPermissionsGranted: () {
Navigator.pushReplacementNamed(context, MainScreen.ID); Navigator.pushReplacementNamed(context, MainScreen.ID);
}, },
), ),
), ),
),
); );
} }
} }

View File

@ -1,7 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/widgets/icon_button_child.dart';
class PermissionsRequiredPage extends StatefulWidget { class PermissionsRequiredPage extends StatefulWidget {
final VoidCallback onPermissionsGranted; final VoidCallback onPermissionsGranted;
@ -61,48 +63,65 @@ class _PermissionsRequiredPageState extends State<PermissionsRequiredPage> {
children: <Widget>[ children: <Widget>[
Text( Text(
localizations.permissionsRequiredPageTitle, localizations.permissionsRequiredPageTitle,
style: Theme.of(context).textTheme.headline1, style: platformThemeData(
context,
material: (data) => data.textTheme.headline1,
cupertino: (data) => data.textTheme.navLargeTitleTextStyle,
),
), ),
const SizedBox(height: MEDIUM_SPACE), const SizedBox(height: MEDIUM_SPACE),
Text(localizations.permissionsRequiredPageDescription), Text(
localizations.permissionsRequiredPageDescription,
style: platformThemeData(
context,
material: (data) => data.textTheme.bodyText1,
cupertino: (data) => data.textTheme.textStyle,
),
),
const SizedBox(height: LARGE_SPACE), const SizedBox(height: LARGE_SPACE),
if (hasDeniedForever) ...[ if (hasDeniedForever) ...[
Text(localizations.permissionsRequiredPagePermanentlyDenied), Text(localizations.permissionsRequiredPagePermanentlyDenied),
const SizedBox(height: LARGE_SPACE), const SizedBox(height: LARGE_SPACE),
TextButton.icon( PlatformElevatedButton(
onPressed: () => openAppSettings(), onPressed: () => openAppSettings(),
icon: const Icon(Icons.settings), child: IconButtonChild(
icon: Icon(context.platformIcons.settings),
label: Text(localizations.permissionsRequiredPageOpenSettings), label: Text(localizations.permissionsRequiredPageOpenSettings),
), ),
),
] else ...[ ] else ...[
TextButton.icon( PlatformTextButton(
onPressed: hasGrantedCameraPermission onPressed: hasGrantedCameraPermission
? null ? null
: () async { : () async {
await Permission.camera.request(); await Permission.camera.request();
await checkPermissions(); await checkPermissions();
}, },
icon: const Icon(Icons.camera_alt), child: IconButtonChild(
icon: Icon(context.platformIcons.photoCamera),
label: Row( label: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Text( Text(
localizations.permissionsRequiredPageGrantCameraPermission, localizations.permissionsRequiredPageGrantCameraPermission,
), ),
if (hasGrantedCameraPermission) const Icon(Icons.check), if (hasGrantedCameraPermission)
Icon(context.platformIcons.checkMark),
if (!hasGrantedCameraPermission) const SizedBox(), if (!hasGrantedCameraPermission) const SizedBox(),
], ],
), ),
), ),
),
const SizedBox(height: MEDIUM_SPACE), const SizedBox(height: MEDIUM_SPACE),
TextButton.icon( PlatformTextButton(
onPressed: hasGrantedMicrophonePermission onPressed: hasGrantedMicrophonePermission
? null ? null
: () async { : () async {
await Permission.microphone.request(); await Permission.microphone.request();
await checkPermissions(); await checkPermissions();
}, },
icon: const Icon(Icons.mic), child: IconButtonChild(
icon: Icon(context.platformIcons.mic),
label: Row( label: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
@ -110,11 +129,13 @@ class _PermissionsRequiredPageState extends State<PermissionsRequiredPage> {
localizations localizations
.permissionsRequiredPageGrantMicrophonePermission, .permissionsRequiredPageGrantMicrophonePermission,
), ),
if (hasGrantedMicrophonePermission) const Icon(Icons.check), if (hasGrantedMicrophonePermission)
Icon(context.platformIcons.checkMark),
if (!hasGrantedMicrophonePermission) const SizedBox(), if (!hasGrantedMicrophonePermission) const SizedBox(),
], ],
), ),
), ),
),
], ],
], ],
); );

View File

@ -1,16 +1,19 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/extensions/snackbar.dart'; import 'package:quid_faciam_hodie/extensions/snackbar.dart';
import 'package:quid_faciam_hodie/managers/authentication_manager.dart'; import 'package:quid_faciam_hodie/managers/authentication_manager.dart';
import 'package:quid_faciam_hodie/screens/server_loading_screen.dart'; import 'package:quid_faciam_hodie/screens/server_loading_screen.dart';
import 'package:quid_faciam_hodie/utils/loadable.dart'; import 'package:quid_faciam_hodie/utils/loadable.dart';
import 'package:quid_faciam_hodie/widgets/icon_button_child.dart';
import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:supabase_flutter/supabase_flutter.dart';
final supabase = Supabase.instance.client; final supabase = Supabase.instance.client;
class LoginScreen extends StatefulWidget { class LoginScreen extends StatefulWidget {
static const ID = 'login'; static const ID = '/login';
const LoginScreen({Key? key}) : super(key: key); const LoginScreen({Key? key}) : super(key: key);
@ -85,10 +88,9 @@ class _LoginScreenState extends AuthState<LoginScreen> with Loadable {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!; final localizations = AppLocalizations.of(context)!;
final theme = Theme.of(context);
return Scaffold( return PlatformScaffold(
appBar: AppBar( appBar: PlatformAppBar(
title: Text(localizations.loginScreenTitle), title: Text(localizations.loginScreenTitle),
), ),
body: Padding( body: Padding(
@ -99,38 +101,63 @@ class _LoginScreenState extends AuthState<LoginScreen> with Loadable {
children: <Widget>[ children: <Widget>[
Text( Text(
localizations.loginScreenTitle, localizations.loginScreenTitle,
style: theme.textTheme.headline1, style: platformThemeData(
context,
material: (data) => data.textTheme.headline1,
cupertino: (data) => data.textTheme.navLargeTitleTextStyle,
),
), ),
const SizedBox(height: LARGE_SPACE), const SizedBox(height: LARGE_SPACE),
Text(localizations.loginScreenHelpText), Text(
localizations.loginScreenHelpText,
style: platformThemeData(
context,
material: (data) => data.textTheme.bodyText1,
cupertino: (data) => data.textTheme.textStyle,
),
),
const SizedBox(height: MEDIUM_SPACE), const SizedBox(height: MEDIUM_SPACE),
TextField( PlatformTextField(
controller: emailController, controller: emailController,
autofocus: true, autofocus: true,
autofillHints: const [AutofillHints.email], autofillHints: const [AutofillHints.email],
keyboardType: TextInputType.emailAddress, keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
material: (_, __) => MaterialTextFieldData(
decoration: InputDecoration( decoration: InputDecoration(
labelText: localizations.loginScreenFormEmailLabel, labelText: localizations.loginScreenFormEmailLabel,
prefixIcon: const Icon(Icons.email), prefixIcon: Icon(context.platformIcons.mail),
),
),
cupertino: (_, __) => CupertinoTextFieldData(
placeholder: localizations.loginScreenFormEmailLabel,
prefix: Icon(context.platformIcons.mail),
), ),
), ),
const SizedBox(height: SMALL_SPACE), const SizedBox(height: SMALL_SPACE),
TextField( PlatformTextField(
obscureText: true, obscureText: true,
controller: passwordController, controller: passwordController,
material: (_, __) => MaterialTextFieldData(
decoration: InputDecoration( decoration: InputDecoration(
labelText: localizations.loginScreenFormPasswordLabel, labelText: localizations.loginScreenFormPasswordLabel,
prefixIcon: const Icon(Icons.lock), prefixIcon: Icon(context.platformIcons.padLock),
),
),
cupertino: (_, __) => CupertinoTextFieldData(
placeholder: localizations.loginScreenFormPasswordLabel,
prefix: Icon(context.platformIcons.padLock),
), ),
onSubmitted: (value) => callWithLoading(signIn), onSubmitted: (value) => callWithLoading(signIn),
), ),
const SizedBox(height: MEDIUM_SPACE), const SizedBox(height: MEDIUM_SPACE),
ElevatedButton.icon( PlatformElevatedButton(
icon: const Icon(Icons.arrow_right),
label: Text(localizations.loginScreenFormSubmitButton),
onPressed: isLoading ? null : () => callWithLoading(signIn), onPressed: isLoading ? null : () => callWithLoading(signIn),
) child: IconButtonChild(
icon: Icon(context.platformIcons.forward),
label: Text(localizations.loginScreenFormSubmitButton),
),
),
], ],
), ),
), ),

View File

@ -5,6 +5,7 @@ import 'package:camera/camera.dart';
import 'package:expandable_bottom_sheet/expandable_bottom_sheet.dart'; import 'package:expandable_bottom_sheet/expandable_bottom_sheet.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/constants/values.dart'; import 'package:quid_faciam_hodie/constants/values.dart';
import 'package:quid_faciam_hodie/extensions/snackbar.dart'; import 'package:quid_faciam_hodie/extensions/snackbar.dart';
@ -23,7 +24,7 @@ import 'main_screen/today_photo_button.dart';
import 'main_screen/uploading_photo.dart'; import 'main_screen/uploading_photo.dart';
class MainScreen extends StatefulWidget { class MainScreen extends StatefulWidget {
static const ID = 'main'; static const ID = '/main';
const MainScreen({Key? key}) : super(key: key); const MainScreen({Key? key}) : super(key: key);
@ -63,7 +64,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
void initState() { void initState() {
super.initState(); super.initState();
onNewCameraSelected(GlobalValuesManager.cameras[0]); loadCameras();
} }
@override @override
@ -77,6 +78,12 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
_updateCamera(state); _updateCamera(state);
} }
Future<void> loadCameras() async {
GlobalValuesManager.setCameras(await availableCameras());
onNewCameraSelected(GlobalValuesManager.cameras[0]);
}
void _updateCamera(final AppLifecycleState state) { void _updateCamera(final AppLifecycleState state) {
final CameraController? cameraController = controller; final CameraController? cameraController = controller;
@ -125,6 +132,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
}); });
await controller!.initialize(); await controller!.initialize();
await controller!.prepareForVideoRecording();
await determineZoomLevels(); await determineZoomLevels();
@ -165,17 +173,18 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
}); });
try { try {
if (isMaterial(context))
context.showPendingSnackBar( context.showPendingSnackBar(
message: localizations.mainScreenTakePhotoActionTakingPhoto, message: localizations.mainScreenTakePhotoActionTakingPhoto,
); );
controller!.setFlashMode(FlashMode.off);
final file = File((await controller!.takePicture()).path); final file = File((await controller!.takePicture()).path);
setState(() { setState(() {
uploadingPhotoAnimation = file.readAsBytesSync(); uploadingPhotoAnimation = file.readAsBytesSync();
}); });
if (isMaterial(context))
context.showPendingSnackBar( context.showPendingSnackBar(
message: localizations.mainScreenTakePhotoActionUploadingPhoto, message: localizations.mainScreenTakePhotoActionUploadingPhoto,
); );
@ -183,10 +192,12 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
try { try {
await FileManager.uploadFile(_user, file); await FileManager.uploadFile(_user, file);
} catch (error) { } catch (error) {
if (isMaterial(context))
context.showErrorSnackBar(message: error.toString()); context.showErrorSnackBar(message: error.toString());
return; return;
} }
if (isMaterial(context))
context.showSuccessSnackBar( context.showSuccessSnackBar(
message: localizations.mainScreenUploadSuccess, message: localizations.mainScreenUploadSuccess,
); );
@ -215,12 +226,14 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
}); });
try { try {
if (isMaterial(context))
context.showPendingSnackBar( context.showPendingSnackBar(
message: localizations.mainScreenTakeVideoActionSaveVideo, message: localizations.mainScreenTakeVideoActionSaveVideo,
); );
final file = File((await controller!.stopVideoRecording()).path); final file = File((await controller!.stopVideoRecording()).path);
if (isMaterial(context))
context.showPendingSnackBar( context.showPendingSnackBar(
message: localizations.mainScreenTakeVideoActionUploadingVideo, message: localizations.mainScreenTakeVideoActionUploadingVideo,
); );
@ -228,12 +241,13 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
try { try {
await FileManager.uploadFile(_user, file); await FileManager.uploadFile(_user, file);
} catch (error) { } catch (error) {
if (mounted) { if (isMaterial(context)) {
context.showErrorSnackBar(message: error.toString()); context.showErrorSnackBar(message: error.toString());
} }
return; return;
} }
if (isMaterial(context))
context.showSuccessSnackBar( context.showSuccessSnackBar(
message: localizations.mainScreenUploadSuccess, message: localizations.mainScreenUploadSuccess,
); );
@ -248,18 +262,25 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!; final localizations = AppLocalizations.of(context)!;
return Scaffold( return PlatformScaffold(
backgroundColor: Colors.black, backgroundColor: Colors.black,
bottomSheet: () { body: () {
if (isLoading) { if (isLoading) {
return Center( return Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
const CircularProgressIndicator(), PlatformCircularProgressIndicator(),
const SizedBox(height: MEDIUM_SPACE), const SizedBox(height: MEDIUM_SPACE),
Text(localizations.mainScreenLoadingCamera), Text(
localizations.mainScreenLoadingCamera,
style: platformThemeData(
context,
material: (data) => data.textTheme.bodyText1,
cupertino: (data) => data.textTheme.textStyle,
),
),
], ],
), ),
); );
@ -304,17 +325,23 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
), ),
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
const Padding( const Padding(
padding: EdgeInsets.symmetric(vertical: MEDIUM_SPACE), padding: EdgeInsets.symmetric(
vertical: MEDIUM_SPACE,
horizontal: MEDIUM_SPACE,
),
child: SheetIndicator(), child: SheetIndicator(),
), ),
Padding( Padding(
padding: const EdgeInsets.all(LARGE_SPACE), padding: const EdgeInsets.symmetric(vertical: SMALL_SPACE),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[ children: <Widget>[
FadeAndMoveInAnimation( Expanded(
child: FadeAndMoveInAnimation(
translationDuration: DEFAULT_TRANSLATION_DURATION * translationDuration: DEFAULT_TRANSLATION_DURATION *
SECONDARY_BUTTONS_DURATION_MULTIPLIER, SECONDARY_BUTTONS_DURATION_MULTIPLIER,
opacityDuration: DEFAULT_OPACITY_DURATION * opacityDuration: DEFAULT_OPACITY_DURATION *
@ -336,7 +363,9 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
}, },
), ),
), ),
FadeAndMoveInAnimation( ),
Expanded(
child: FadeAndMoveInAnimation(
child: RecordButton( child: RecordButton(
disabled: lockCamera, disabled: lockCamera,
active: isRecording, active: isRecording,
@ -356,7 +385,9 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
onPhotoShot: takePhoto, onPhotoShot: takePhoto,
), ),
), ),
FadeAndMoveInAnimation( ),
Expanded(
child: FadeAndMoveInAnimation(
translationDuration: DEFAULT_TRANSLATION_DURATION * translationDuration: DEFAULT_TRANSLATION_DURATION *
SECONDARY_BUTTONS_DURATION_MULTIPLIER, SECONDARY_BUTTONS_DURATION_MULTIPLIER,
opacityDuration: DEFAULT_OPACITY_DURATION * opacityDuration: DEFAULT_OPACITY_DURATION *
@ -372,13 +403,16 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
}, },
), ),
), ),
),
], ],
), ),
), ),
], ],
), ),
), ),
expandableContent: Padding( expandableContent: Container(
color: Colors.black,
child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: LARGE_SPACE, left: LARGE_SPACE,
right: LARGE_SPACE, right: LARGE_SPACE,
@ -392,10 +426,12 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
label: Text(AppLocalizations.of(context)! label: Text(AppLocalizations.of(context)!
.mainScreenActionsTorchButton), .mainScreenActionsTorchButton),
style: ButtonStyle( style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith<Color>( backgroundColor:
MaterialStateProperty.resolveWith<Color>(
(_) => isTorchEnabled ? Colors.white : Colors.black, (_) => isTorchEnabled ? Colors.white : Colors.black,
), ),
foregroundColor: MaterialStateProperty.resolveWith<Color>( foregroundColor:
MaterialStateProperty.resolveWith<Color>(
(_) => isTorchEnabled ? Colors.black : Colors.white, (_) => isTorchEnabled ? Colors.black : Colors.white,
), ),
), ),
@ -413,10 +449,12 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
), ),
ElevatedButton( ElevatedButton(
style: ButtonStyle( style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith<Color>( backgroundColor:
MaterialStateProperty.resolveWith<Color>(
(_) => Colors.white10, (_) => Colors.white10,
), ),
foregroundColor: MaterialStateProperty.resolveWith<Color>( foregroundColor:
MaterialStateProperty.resolveWith<Color>(
(_) => Colors.white, (_) => Colors.white,
), ),
), ),
@ -444,6 +482,7 @@ class _MainScreenState extends AuthRequiredState<MainScreen> with Loadable {
), ),
), ),
), ),
),
); );
}(), }(),
); );

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
class ChangeCameraButton extends StatelessWidget { class ChangeCameraButton extends StatelessWidget {
final VoidCallback onChangeCamera; final VoidCallback onChangeCamera;
@ -13,9 +14,7 @@ class ChangeCameraButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return InkWell( return GestureDetector(
enableFeedback: false,
highlightColor: Colors.transparent,
onTap: () { onTap: () {
if (disabled) { if (disabled) {
return; return;
@ -34,9 +33,9 @@ class ChangeCameraButton extends StatelessWidget {
size: 60, size: 60,
color: Colors.white.withOpacity(.2), color: Colors.white.withOpacity(.2),
), ),
const Icon( Icon(
Icons.camera_alt, context.platformIcons.switchCamera,
size: 30, size: 25,
color: Colors.white, color: Colors.white,
), ),
], ],

View File

@ -28,6 +28,17 @@ class _RecordButtonState extends State<RecordButton> {
bool animateToVideoIcon = false; bool animateToVideoIcon = false;
bool videoInAnimationActive = false; bool videoInAnimationActive = false;
void cancelAnimation() {
if (videoInAnimationActive || animateToVideoIcon) {
return;
}
setState(() {
videoInAnimationActive = false;
animateToVideoIcon = false;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
@ -57,6 +68,7 @@ class _RecordButtonState extends State<RecordButton> {
} }
setState(() { setState(() {
animateToVideoIcon = false;
videoInAnimationActive = true; videoInAnimationActive = true;
}); });
@ -96,70 +108,70 @@ class _RecordButtonState extends State<RecordButton> {
}); });
}, },
// Cancel icon animation // Cancel icon animation
onTapCancel: () { onTapCancel: cancelAnimation,
if (videoInAnimationActive || animateToVideoIcon) { onPanCancel: cancelAnimation,
return; onLongPressCancel: cancelAnimation,
}
setState(() {
videoInAnimationActive = false;
animateToVideoIcon = false;
});
},
// Cancel icon animation
onPanCancel: () {
if (videoInAnimationActive || animateToVideoIcon) {
return;
}
setState(() {
videoInAnimationActive = false;
animateToVideoIcon = false;
});
},
child: Opacity( child: Opacity(
opacity: widget.disabled ? 0.5 : 1.0, opacity: widget.disabled ? 0.5 : 1.0,
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: <Widget>[ children: <Widget>[
Icon( AnimatedContainer(
Icons.circle, duration: videoInAnimationActive ? Duration.zero : OUT_DURATION,
size: 75, width: 60,
color: Colors.white.withOpacity(.2), height: 60,
decoration: BoxDecoration(
color: videoInAnimationActive
? Colors.white
: Colors.white.withOpacity(.2),
borderRadius: BorderRadius.circular(30),
),
), ),
AnimatedScale( AnimatedScale(
duration: animateToVideoIcon ? kLongPressTimeout : OUT_DURATION, duration: () {
if (videoInAnimationActive) {
return Duration(milliseconds: 400);
}
if (animateToVideoIcon) {
return kLongPressTimeout;
}
return OUT_DURATION;
}(),
curve: Curves.easeInOut, curve: Curves.easeInOut,
scale: animateToVideoIcon ? (75 / 50) : 1, scale: () {
child: const Icon( if (videoInAnimationActive) {
Icons.circle, return .6;
size: 50, }
color: Colors.white,
if (animateToVideoIcon) {
return 60 / 40;
}
return 1.0;
}(),
child: AnimatedContainer(
duration: () {
if (videoInAnimationActive) {
return Duration(milliseconds: 400);
}
if (animateToVideoIcon) {
return kLongPressTimeout;
}
return OUT_DURATION;
}(),
width: 40,
height: 40,
decoration: BoxDecoration(
color: videoInAnimationActive ? Colors.red : Colors.white,
borderRadius: videoInAnimationActive
? BorderRadius.circular(4)
: BorderRadius.circular(50),
), ),
), ),
AnimatedScale(
curve: Curves.easeInOut,
duration: animateToVideoIcon
? const Duration(milliseconds: 180)
: OUT_DURATION,
scale: videoInAnimationActive ? 1 : 0,
child: const Icon(
Icons.circle,
size: 65,
color: Colors.red,
),
),
AnimatedScale(
curve: animateToVideoIcon ? Curves.easeOut : Curves.linear,
duration: animateToVideoIcon
? const Duration(milliseconds: 250)
: OUT_DURATION,
scale: videoInAnimationActive ? 1 : .6,
child: const Icon(
Icons.stop,
size: 45,
color: Colors.white,
),
), ),
], ],
), ),

View File

@ -70,7 +70,7 @@ class _TodayPhotoButtonState extends State<TodayPhotoButton> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return InkWell( return GestureDetector(
onTap: () async { onTap: () async {
widget.onLeave(); widget.onLeave();
@ -85,6 +85,7 @@ class _TodayPhotoButtonState extends State<TodayPhotoButton> {
widget.onComeBack(); widget.onComeBack();
}, },
child: Align(
child: Container( child: Container(
width: 45, width: 45,
height: 45, height: 45,
@ -106,6 +107,7 @@ class _TodayPhotoButtonState extends State<TodayPhotoButton> {
), ),
), ),
), ),
),
); );
} }
} }

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/managers/global_values_manager.dart'; import 'package:quid_faciam_hodie/managers/global_values_manager.dart';
@ -11,7 +12,7 @@ import 'server_loading_screen/dot_animation.dart';
import 'welcome_screen.dart'; import 'welcome_screen.dart';
class ServerLoadingScreen extends StatefulWidget { class ServerLoadingScreen extends StatefulWidget {
static const ID = 'server_loading'; static const ID = '/server_loading';
final String? nextScreen; final String? nextScreen;
@ -63,7 +64,11 @@ class _ServerLoadingScreenState extends State<ServerLoadingScreen> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
const Icon(Icons.cloud, size: 60), const Icon(
Icons.cloud,
size: 60,
color: Colors.white,
),
const SizedBox(height: SMALL_SPACE), const SizedBox(height: SMALL_SPACE),
const DotAnimation( const DotAnimation(
initialFadeInDelay: Duration.zero, initialFadeInDelay: Duration.zero,
@ -87,9 +92,20 @@ class _ServerLoadingScreenState extends State<ServerLoadingScreen> {
fadeOutDelay: Duration.zero, fadeOutDelay: Duration.zero,
), ),
const SizedBox(height: SMALL_SPACE), const SizedBox(height: SMALL_SPACE),
const Icon(Icons.smartphone, size: 60), const Icon(
Icons.phone_android_rounded,
size: 60,
color: Colors.white,
),
const SizedBox(height: LARGE_SPACE), const SizedBox(height: LARGE_SPACE),
Text(localizations.serverLoadingScreenDescription), Text(
localizations.serverLoadingScreenDescription,
style: platformThemeData(
context,
material: (data) => data.textTheme.bodyText1,
cupertino: (data) => data.textTheme.textStyle,
),
),
], ],
), ),
), ),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:quid_faciam_hodie/extensions/date.dart'; import 'package:quid_faciam_hodie/extensions/date.dart';
import 'package:quid_faciam_hodie/models/memories.dart'; import 'package:quid_faciam_hodie/models/memories.dart';
@ -12,7 +13,7 @@ import 'timeline_screen/timeline_page.dart';
final supabase = Supabase.instance.client; final supabase = Supabase.instance.client;
class TimelineScreen extends StatefulWidget { class TimelineScreen extends StatefulWidget {
static const ID = 'timeline'; static const ID = '/timeline';
final DateTime? date; final DateTime? date;
@ -92,7 +93,12 @@ class _TimelineScreenState extends State<TimelineScreen> with Loadable {
return true; return true;
}, },
child: Scaffold( child: PlatformScaffold(
appBar: isCupertino(context)
? PlatformAppBar(
title: Text('Timeline'),
)
: null,
body: ChangeNotifierProvider.value( body: ChangeNotifierProvider.value(
value: timeline, value: timeline,
child: PageView.builder( child: PageView.builder(

View File

@ -3,6 +3,7 @@ import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/enums.dart'; import 'package:quid_faciam_hodie/enums.dart';
import 'package:quid_faciam_hodie/foreign_types/memory.dart'; import 'package:quid_faciam_hodie/foreign_types/memory.dart';
@ -81,15 +82,20 @@ class _MemoryViewState extends State<MemoryView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!; final localizations = AppLocalizations.of(context)!;
final theme = Theme.of(context);
if (status == MemoryFetchStatus.error) { if (status == MemoryFetchStatus.error) {
return Center( return Center(
child: Text( child: Text(
localizations.memoryViewDownloadFailed, localizations.memoryViewDownloadFailed,
style: theme.textTheme.bodyText2!.copyWith( style: platformThemeData(
context,
material: (data) => data.textTheme.bodyText2!.copyWith(
color: Colors.white, color: Colors.white,
), ),
cupertino: (data) => data.textTheme.textStyle.copyWith(
color: Colors.white,
),
),
), ),
); );
} }
@ -126,16 +132,22 @@ class _MemoryViewState extends State<MemoryView> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
const CircularProgressIndicator(), PlatformCircularProgressIndicator(),
const SizedBox(height: SMALL_SPACE), const SizedBox(height: SMALL_SPACE),
() { () {
switch (status) { switch (status) {
case MemoryFetchStatus.downloading: case MemoryFetchStatus.downloading:
return Text( return Text(
localizations.memoryViewIsDownloading, localizations.memoryViewIsDownloading,
style: theme.textTheme.bodyText2!.copyWith( style: platformThemeData(
context,
material: (data) => data.textTheme.bodyText2!.copyWith(
color: Colors.white, color: Colors.white,
), ),
cupertino: (data) => data.textTheme.textStyle.copyWith(
color: Colors.white,
),
),
); );
default: default:
return const SizedBox(); return const SizedBox();

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart';
@ -18,14 +19,14 @@ class TimelineOverlay extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context);
final timeline = context.watch<TimelineModel>(); final timeline = context.watch<TimelineModel>();
return Stack( return Stack(
children: <Widget>[ children: <Widget>[
Padding( Padding(
padding: const EdgeInsets.only( padding: EdgeInsets.only(
top: LARGE_SPACE, // Cupertino needs more space as the top bar is shown to provide a pop button
top: isCupertino(context) ? HUGE_SPACE : LARGE_SPACE,
left: MEDIUM_SPACE, left: MEDIUM_SPACE,
right: MEDIUM_SPACE, right: MEDIUM_SPACE,
), ),
@ -36,9 +37,16 @@ class TimelineOverlay extends StatelessWidget {
child: Text( child: Text(
DateFormat.yMMMd().format(date), DateFormat.yMMMd().format(date),
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline1!.copyWith( style: platformThemeData(
context,
material: (data) => data.textTheme.headline1!.copyWith(
color: Colors.white, color: Colors.white,
), ),
cupertino: (data) =>
data.textTheme.navLargeTitleTextStyle.copyWith(
color: Colors.white,
),
),
), ),
), ),
), ),
@ -59,16 +67,27 @@ class TimelineOverlay extends StatelessWidget {
curve: Curves.linearToEaseOut, curve: Curves.linearToEaseOut,
child: Icon( child: Icon(
Icons.public, Icons.public,
size: theme.textTheme.titleSmall!.fontSize, size: platformThemeData(
context,
material: (data) => data.textTheme.bodyLarge!.fontSize,
cupertino: (data) => data.textTheme.textStyle.fontSize,
),
color: Colors.white, color: Colors.white,
), ),
), ),
const SizedBox(width: SMALL_SPACE), const SizedBox(width: SMALL_SPACE),
Text( Text(
'$memoryIndex/$memoriesAmount', '$memoryIndex/$memoriesAmount',
style: Theme.of(context).textTheme.titleSmall!.copyWith( style: platformThemeData(
context,
material: (data) => data.textTheme.titleSmall!.copyWith(
color: Colors.white, color: Colors.white,
), ),
cupertino: (data) =>
data.textTheme.navTitleTextStyle.copyWith(
color: Colors.white,
),
),
) )
], ],
), ),

View File

@ -1,59 +1,75 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:quid_faciam_hodie/constants/spacing.dart'; import 'package:quid_faciam_hodie/constants/spacing.dart';
import 'package:quid_faciam_hodie/widgets/icon_button_child.dart';
import 'package:quid_faciam_hodie/widgets/logo.dart'; import 'package:quid_faciam_hodie/widgets/logo.dart';
import 'grant_permission_screen.dart'; import 'grant_permission_screen.dart';
class WelcomeScreen extends StatelessWidget { class WelcomeScreen extends StatelessWidget {
static const ID = 'welcome'; static const ID = '/';
const WelcomeScreen({Key? key}) : super(key: key); const WelcomeScreen({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!; final localizations = AppLocalizations.of(context)!;
final theme = Theme.of(context);
return Scaffold( return PlatformScaffold(
body: Padding( body: Padding(
padding: const EdgeInsets.all(MEDIUM_SPACE), padding: const EdgeInsets.all(MEDIUM_SPACE),
child: Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
const Logo(), const Logo(),
const SizedBox(height: LARGE_SPACE), const SizedBox(height: LARGE_SPACE),
Text( Text(
localizations.appTitleQuestion, localizations.appTitleQuestion,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: theme.textTheme.headline1, style: platformThemeData(
context,
material: (data) => data.textTheme.headline1,
cupertino: (data) => data.textTheme.navLargeTitleTextStyle,
),
), ),
const SizedBox(height: SMALL_SPACE), const SizedBox(height: SMALL_SPACE),
Text( Text(
localizations.welcomeScreenSubtitle, localizations.welcomeScreenSubtitle,
style: theme.textTheme.bodySmall, style: platformThemeData(
context,
material: (data) => data.textTheme.bodySmall,
cupertino: (data) => data.textTheme.navTitleTextStyle,
),
), ),
const SizedBox(height: LARGE_SPACE), const SizedBox(height: LARGE_SPACE),
Text( Text(
localizations.welcomeScreenDescription, localizations.welcomeScreenDescription,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: theme.textTheme.bodyText2, style: platformThemeData(
context,
material: (data) => data.textTheme.bodyText1,
cupertino: (data) => data.textTheme.textStyle,
),
), ),
const SizedBox(height: LARGE_SPACE), const SizedBox(height: LARGE_SPACE),
ElevatedButton.icon( PlatformElevatedButton(
icon: const Icon(Icons.arrow_right), child: IconButtonChild(
icon: Icon(context.platformIcons.forward),
label: Text(localizations.welcomeScreenStartButtonTitle), label: Text(localizations.welcomeScreenStartButtonTitle),
),
onPressed: () { onPressed: () {
Navigator.pushReplacementNamed( Navigator.pushReplacementNamed(
context, context,
GrantPermissionScreen.ID, GrantPermissionScreen.ID,
); );
}, },
), )
], ],
), ),
), ),
),
); );
} }
} }

View File

@ -0,0 +1,30 @@
import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
class IconButtonChild extends StatelessWidget {
final Widget label;
final Widget icon;
const IconButtonChild({
Key? key,
required this.label,
required this.icon,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final double scale = MediaQuery.maybeOf(context)?.textScaleFactor ?? 1;
final double gap = scale <= 1 ? 8 : lerpDouble(8, 4, min(scale - 1, 1))!;
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
icon,
SizedBox(width: gap),
Flexible(child: label),
],
);
}
}

View File

@ -158,6 +158,13 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_platform_widgets:
dependency: "direct main"
description:
name: flutter_platform_widgets
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: transitive
description: description:

View File

@ -53,6 +53,7 @@ dependencies:
expandable_bottom_sheet: ^1.1.1+1 expandable_bottom_sheet: ^1.1.1+1
flutter_sticky_header: ^0.6.4 flutter_sticky_header: ^0.6.4
flutter_calendar_widget: ^0.0.2 flutter_calendar_widget: ^0.0.2
flutter_platform_widgets: ^2.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: