diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 6b4c0f7..f2872cf 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 8.0
+ 9.0
diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig
index 592ceee..ec97fc6 100644
--- a/ios/Flutter/Debug.xcconfig
+++ b/ios/Flutter/Debug.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig
index 592ceee..c4855bf 100644
--- a/ios/Flutter/Release.xcconfig
+++ b/ios/Flutter/Release.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
diff --git a/ios/Podfile b/ios/Podfile
new file mode 100644
index 0000000..1e8c3c9
--- /dev/null
+++ b/ios/Podfile
@@ -0,0 +1,41 @@
+# Uncomment this line to define a global platform for your project
+# platform :ios, '9.0'
+
+# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
+ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+
+project 'Runner', {
+ 'Debug' => :debug,
+ 'Profile' => :release,
+ 'Release' => :release,
+}
+
+def flutter_root
+ generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
+ unless File.exist?(generated_xcode_build_settings_path)
+ raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
+ end
+
+ File.foreach(generated_xcode_build_settings_path) do |line|
+ matches = line.match(/FLUTTER_ROOT\=(.*)/)
+ return matches[1].strip if matches
+ end
+ raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
+end
+
+require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
+
+flutter_ios_podfile_setup
+
+target 'Runner' do
+ use_frameworks!
+ use_modular_headers!
+
+ flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ flutter_additional_ios_build_settings(target)
+ end
+end
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
new file mode 100644
index 0000000..3ff3c07
--- /dev/null
+++ b/ios/Podfile.lock
@@ -0,0 +1,22 @@
+PODS:
+ - Flutter (1.0.0)
+ - path_provider_ios (0.0.1):
+ - Flutter
+
+DEPENDENCIES:
+ - Flutter (from `Flutter`)
+ - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
+
+EXTERNAL SOURCES:
+ Flutter:
+ :path: Flutter
+ path_provider_ios:
+ :path: ".symlinks/plugins/path_provider_ios/ios"
+
+SPEC CHECKSUMS:
+ Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
+ path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
+
+PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
+
+COCOAPODS: 1.11.2
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 1d8d1bb..bc5318c 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -13,6 +13,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+ AD12A159508116180CA4DBF8 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 254FCDD86784C532FE0FF549 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -31,7 +32,9 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 254FCDD86784C532FE0FF549 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 51793B029BCFD0D9F974B68A /* 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 = ""; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
@@ -42,6 +45,8 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ BEF81072DE02D05E1B9A8DB8 /* 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 = ""; };
+ E872E74B552E8BFDFAD7EA8F /* 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 = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -49,12 +54,32 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ AD12A159508116180CA4DBF8 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 66CE2ECF7C5B7EBD0E9D08A8 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 254FCDD86784C532FE0FF549 /* Pods_Runner.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 8604D50E6F34494DF5D8D7EF /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 51793B029BCFD0D9F974B68A /* Pods-Runner.debug.xcconfig */,
+ E872E74B552E8BFDFAD7EA8F /* Pods-Runner.release.xcconfig */,
+ BEF81072DE02D05E1B9A8DB8 /* Pods-Runner.profile.xcconfig */,
+ );
+ name = Pods;
+ path = Pods;
+ sourceTree = "";
+ };
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@@ -72,6 +97,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
+ 8604D50E6F34494DF5D8D7EF /* Pods */,
+ 66CE2ECF7C5B7EBD0E9D08A8 /* Frameworks */,
);
sourceTree = "";
};
@@ -105,12 +132,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
+ 3FC32931F529AB48128449B9 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ B5F1519081B4E2E2B4548568 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -183,6 +212,28 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
+ 3FC32931F529AB48128449B9 /* [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;
+ };
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -197,6 +248,23 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
+ B5F1519081B4E2E2B4548568 /* [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;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
index 1d526a1..919434a 100644
--- a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -2,6 +2,6 @@
+ location = "self:">
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata
index 1d526a1..21a3cc1 100644
--- a/ios/Runner.xcworkspace/contents.xcworkspacedata
+++ b/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -4,4 +4,7 @@
+
+
diff --git a/lib/logic/bloc/calculator_bloc.dart b/lib/logic/bloc/calculator_bloc.dart
new file mode 100644
index 0000000..01e32c5
--- /dev/null
+++ b/lib/logic/bloc/calculator_bloc.dart
@@ -0,0 +1,122 @@
+import 'package:bloc/bloc.dart';
+import 'package:expression_language/expression_language.dart';
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+import 'package:meta/meta.dart';
+import 'dart:convert';
+part 'calculator_event.dart';
+part 'calculator_state.dart';
+
+class CalculatorBloc extends Bloc
+ with HydratedMixin {
+ CalculatorBloc() : super(CalculatorState(text: "")) {}
+
+ var expressionGrammarDefinition = ExpressionGrammarParser({});
+
+ @override
+ Stream mapEventToState(
+ CalculatorEvent event,
+ ) async* {
+ if (event is CalculatorAddEvent) {
+ if (event.character == 'C') {
+ yield state.copyWith(text: "", result: "");
+ } else if (event.character == '=') {
+ if (state.results.isNotEmpty &&
+ state.results.last.result == state.text) {
+ print("Www");
+ } else {
+ var parser = expressionGrammarDefinition.build();
+
+ try {
+ var now = state.text;
+ if (now.endsWith('%')) {
+ now = '/100';
+ } else if (now.contains('%')) {
+ now = '/100*';
+ }
+
+ var result = parser.parse(state.text.replaceFirst('%', now));
+ var expression = result.value as Expression;
+ var value = expression.evaluate();
+
+ List cal = state.results.toList();
+
+ if (cal.length > 10) {
+ cal.removeLast();
+ }
+
+ cal.add(Result(result: value.toString(), data: state.text));
+
+ yield state.copyWith(
+ text: value.toString(), result: "", results: cal);
+
+ print(state
+ .copyWith(
+ text: "",
+ result: "",
+ )
+ .toJson());
+ } catch (e) {
+ print(e);
+ yield state.copyWith(
+ text: "Invalid",
+ );
+ }
+ }
+ } else {
+ yield state.copyWith(text: state.text + event.character);
+
+ var parser = expressionGrammarDefinition.build();
+ try {
+ var now = state.text;
+ if (now.endsWith('%')) {
+ now = '/100';
+ } else if (now.contains('%')) {
+ now = '/100*';
+ }
+
+ var result = parser.parse(state.text.replaceFirst('%', now));
+ var expression = result.value as Expression;
+ var value = expression.evaluate();
+ yield state.copyWith(text: state.text, result: value.toString());
+ } catch (e) {
+ yield state.copyWith(text: state.text, result: "");
+ }
+ }
+ } else if (event is CalculatorResultEvent) {
+ yield state.copyWith(text: event.result);
+ } else if (event is CalculatorBackEvent) {
+ yield state.copyWith(
+ text: state.text.substring(0, state.text.length - 1));
+
+ var parser = expressionGrammarDefinition.build();
+ try {
+ var now = state.text;
+ if (now.endsWith('%')) {
+ now = '/100';
+ } else if (now.contains('%')) {
+ now = '/100*';
+ }
+
+ var result = parser.parse(state.text.replaceFirst('%', now));
+ var expression = result.value as Expression;
+ var value = expression.evaluate();
+ yield state.copyWith(text: state.text, result: value.toString());
+ } catch (e) {
+ yield state.copyWith(text: state.text, result: "");
+ }
+ }
+ }
+
+ @override
+ CalculatorState? fromJson(Map json) {
+ if (json != null) {
+ return CalculatorState.fromMap(json);
+ }
+ return CalculatorState(text: "");
+ }
+
+ @override
+ Map? toJson(CalculatorState state) {
+ return state.toMap();
+ }
+}
diff --git a/lib/logic/bloc/calculator_event.dart b/lib/logic/bloc/calculator_event.dart
new file mode 100644
index 0000000..89716fc
--- /dev/null
+++ b/lib/logic/bloc/calculator_event.dart
@@ -0,0 +1,20 @@
+part of 'calculator_bloc.dart';
+
+@immutable
+abstract class CalculatorEvent {}
+
+class CalculatorAddEvent extends CalculatorEvent {
+ String character;
+ CalculatorAddEvent({
+ required this.character,
+ });
+}
+
+class CalculatorResultEvent extends CalculatorEvent {
+ String result;
+ CalculatorResultEvent({
+ required this.result,
+ });
+}
+
+class CalculatorBackEvent extends CalculatorEvent {}
diff --git a/lib/logic/bloc/calculator_state.dart b/lib/logic/bloc/calculator_state.dart
new file mode 100644
index 0000000..1161031
--- /dev/null
+++ b/lib/logic/bloc/calculator_state.dart
@@ -0,0 +1,72 @@
+part of 'calculator_bloc.dart';
+
+class Result {
+ String result;
+ String data;
+ Result({
+ required this.result,
+ required this.data,
+ });
+
+ Map toMap() {
+ return {
+ 'result': result,
+ 'data': data,
+ };
+ }
+
+ factory Result.fromMap(Map map) {
+ return Result(
+ result: map['result'],
+ data: map['data'],
+ );
+ }
+
+ String toJson() => json.encode(toMap());
+
+ factory Result.fromJson(String source) => Result.fromMap(json.decode(source));
+}
+
+class CalculatorState {
+ String text;
+ String result;
+ List results;
+ CalculatorState({
+ required this.text,
+ this.result = '',
+ this.results = const [],
+ });
+
+ CalculatorState copyWith({
+ String? text,
+ String? result,
+ List? results,
+ }) {
+ return CalculatorState(
+ text: text ?? this.text,
+ result: result ?? this.result,
+ results: results ?? this.results,
+ );
+ }
+
+ Map toMap() {
+ return {
+ 'text': text,
+ 'result': result,
+ 'results': results.map((x) => x.toMap()).toList(),
+ };
+ }
+
+ factory CalculatorState.fromMap(Map map) {
+ return CalculatorState(
+ text: map['text'],
+ result: map['result'],
+ results: List.from(map['results']?.map((x) => Result.fromMap(x))),
+ );
+ }
+
+ String toJson() => json.encode(toMap());
+
+ factory CalculatorState.fromJson(String source) =>
+ CalculatorState.fromMap(json.decode(source));
+}
diff --git a/lib/main.dart b/lib/main.dart
index 29d8183..4a9a757 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,22 +1,32 @@
-import 'package:calc_challenge/screens/home.dart';
+import 'package:cal/logic/bloc/calculator_bloc.dart';
import 'package:flutter/material.dart';
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+import 'package:sizer/sizer.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'ui/screens/home_page.dart';
+import 'package:path_provider/path_provider.dart';
-void main() {
- runApp(Calc());
+void main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+ HydratedBloc.storage = await HydratedStorage.build(
+ storageDirectory: await getApplicationDocumentsDirectory());
+ runApp(const MyApp());
}
-class Calc extends StatefulWidget {
- @override
- _CalcState createState() => _CalcState();
-}
+class MyApp extends StatelessWidget {
+ const MyApp({Key? key}) : super(key: key);
-class _CalcState extends State {
@override
Widget build(BuildContext context) {
- return MaterialApp(
- title: 'A simple calculator app',
- // routes: ,
- home: Home(),
+ return Sizer(
+ builder: (context, constraints, orientation) => MaterialApp(
+ theme: ThemeData.dark(),
+ home: BlocProvider(
+ create: (context) => CalculatorBloc(),
+ child: MyHomePage(),
+ lazy: false,
+ ),
+ ),
);
}
}
diff --git a/lib/nav/appbar.dart b/lib/nav/appbar.dart
deleted file mode 100644
index c01cc47..0000000
--- a/lib/nav/appbar.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-import 'package:flutter/material.dart';
-
-class CustomNav extends StatelessWidget with PreferredSizeWidget {
- @override
- Widget build(BuildContext context) {
- return AppBar(
- title: Text('Calculator'),
- );
- }
-
- @override
- // TODO: implement preferredSize
- Size get preferredSize => Size.fromHeight(40.0);
-}
diff --git a/lib/screens/home.dart b/lib/screens/home.dart
deleted file mode 100644
index a67ccae..0000000
--- a/lib/screens/home.dart
+++ /dev/null
@@ -1,30 +0,0 @@
-import 'package:calc_challenge/nav/appbar.dart';
-import 'package:flutter/material.dart';
-
-class Home extends StatefulWidget {
- @override
- _HomeState createState() => _HomeState();
-}
-
-class _HomeState extends State {
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: CustomNav(),
- body: Column(
- children: [
- Row(
- children: [
- Text('Implement display here'),
- ],
- ),
- Row(
- children: [
- Text('Implement interaction buttons here'),
- ],
- )
- ],
- ),
- );
- }
-}
diff --git a/lib/ui/screens/home_page.dart b/lib/ui/screens/home_page.dart
new file mode 100644
index 0000000..17abf31
--- /dev/null
+++ b/lib/ui/screens/home_page.dart
@@ -0,0 +1,248 @@
+import 'dart:ui';
+
+import 'package:cal/logic/bloc/calculator_bloc.dart';
+import 'package:flutter/material.dart';
+import 'package:sizer/sizer.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class MyHomePage extends StatelessWidget {
+ void show(BuildContext ctx) {
+ showModalBottomSheet(
+ backgroundColor: Colors.white10,
+ barrierColor: Colors.black,
+ isScrollControlled: true,
+ context: ctx,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.only(
+ topLeft: Radius.circular(50), topRight: Radius.circular(50))),
+ builder: (context) {
+ return BlocProvider.value(
+ value: BlocProvider.of(ctx),
+ child: Container(
+ padding: EdgeInsets.all(20),
+ height: 80.0.h,
+ child: BlocBuilder(
+ builder: (context, state) {
+ List results = state.results.reversed.toList();
+ return ListView.builder(
+ itemCount: state.results.length,
+ itemBuilder: (context, index) {
+ return Container(
+ decoration: const BoxDecoration(
+ border: Border(bottom: BorderSide(width: 0.5))),
+ child: ListTile(
+ onTap: () {
+ context.read().add(
+ CalculatorResultEvent(
+ result: results[index].result));
+ Navigator.pop(context);
+ },
+ title: Text(
+ results[index].result,
+ style: TextStyle(fontSize: 30.0.sp),
+ ),
+ subtitle: Text(
+ results[index].data,
+ style: TextStyle(fontSize: 20.0.sp),
+ ),
+ ),
+ );
+ });
+ },
+ )),
+ );
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.white10,
+ appBar: AppBar(
+ backgroundColor: Colors.black,
+ title: Text(
+ "Calculator",
+ style: TextStyle(fontSize: 20.0.sp),
+ ),
+ elevation: 0,
+ actions: [
+ InkWell(
+ onTap: () {
+ show(context);
+ },
+ child: Container(
+ margin: const EdgeInsets.only(right: 15),
+ child: const Icon(
+ Icons.history,
+ size: 30,
+ )),
+ )
+ ],
+ ),
+ body: Column(
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ Container(
+ height: 35.0.h,
+ // margin: EdgeInsets.symmetric(horizontal: 5.0.w),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Container(
+ width: 90.0.w,
+ decoration: const BoxDecoration(
+ border: Border(
+ bottom: BorderSide(width: 2, color: Colors.black12))),
+ alignment: Alignment.centerRight,
+ child: SingleChildScrollView(
+ scrollDirection: Axis.horizontal,
+ child: Text(
+ context.watch().state.text,
+ textAlign: TextAlign.end,
+ overflow: TextOverflow.clip,
+ style: TextStyle(fontSize: 50.0.sp),
+ ),
+ ),
+ ),
+ Container(
+ width: 80.0.w,
+ child: Text(
+ context.watch().state.result,
+ textAlign: TextAlign.end,
+ style: TextStyle(fontSize: 30.0.sp),
+ ),
+ )
+ ],
+ ),
+ ),
+ Flexible(
+ child: Container(
+ width: double.infinity,
+ padding: EdgeInsets.symmetric(vertical: 2.0.h),
+ color: Colors.black,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomContainer("("),
+ CustomContainer(")"),
+ CustomContainer("="),
+ CustomCircleContainer("C"),
+ ],
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomContainer("1"),
+ CustomContainer("2"),
+ CustomContainer("3"),
+ CustomCircleContainer("/"),
+ ],
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomContainer("7"),
+ CustomContainer("8"),
+ CustomContainer("9"),
+ CustomCircleContainer("*"),
+ ],
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomContainer("4"),
+ CustomContainer("5"),
+ CustomContainer("6"),
+ CustomCircleContainer("-"),
+ ],
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomContainer("1"),
+ CustomContainer("2"),
+ CustomContainer("3"),
+ CustomCircleContainer("+"),
+ ],
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ CustomContainer("0"),
+ CustomContainer("%"),
+ CustomContainer("."),
+ InkWell(
+ onTap: () {
+ context
+ .read()
+ .add(CalculatorBackEvent());
+ },
+ child: Container(
+ width: 20.0.w,
+ alignment: Alignment.center,
+ child: Icon(
+ Icons.backspace,
+ size: 25,
+ color: Colors.pinkAccent,
+ ),
+ ),
+ )
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class CustomContainer extends StatelessWidget {
+ final String text;
+ CustomContainer(this.text);
+
+ @override
+ Widget build(BuildContext context) {
+ return InkWell(
+ onTap: () {
+ context.read().add(CalculatorAddEvent(character: text));
+ },
+ child: Container(
+ width: 20.0.w,
+ alignment: Alignment.center,
+ child: Text(
+ text,
+ textAlign: TextAlign.center,
+ style: TextStyle(fontSize: 30.0.sp),
+ ),
+ ),
+ );
+ }
+}
+
+class CustomCircleContainer extends StatelessWidget {
+ final String text;
+ CustomCircleContainer(this.text);
+
+ @override
+ Widget build(BuildContext context) {
+ return InkWell(
+ onTap: () {
+ context.read().add(CalculatorAddEvent(character: text));
+ },
+ child: Container(
+ width: 20.0.w,
+ alignment: Alignment.center,
+ child: Text(
+ text,
+ style: TextStyle(fontSize: 30.0.sp, color: Colors.pinkAccent),
+ ),
+ ),
+ );
+ }
+}
diff --git a/pubspec.lock b/pubspec.lock
index d59718c..8fde649 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -7,7 +7,14 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
- version: "2.5.0"
+ version: "2.8.1"
+ bloc:
+ dependency: transitive
+ description:
+ name: bloc
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "7.2.1"
boolean_selector:
dependency: transitive
description:
@@ -28,7 +35,7 @@ packages:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
- version: "1.2.0"
+ version: "1.3.1"
clock:
dependency: transitive
description:
@@ -43,13 +50,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.15.0"
+ crypto:
+ dependency: transitive
+ description:
+ name: crypto
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.0.1"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
source: hosted
- version: "1.0.1+1"
+ version: "1.0.4"
+ expression_language:
+ dependency: "direct main"
+ description:
+ name: expression_language
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.1"
fake_async:
dependency: transitive
description:
@@ -57,16 +78,65 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
+ ffi:
+ dependency: transitive
+ description:
+ name: ffi
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.1.2"
+ file:
+ dependency: transitive
+ description:
+ name: file
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "6.1.2"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
+ flutter_bloc:
+ dependency: "direct main"
+ description:
+ name: flutter_bloc
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "7.3.3"
+ flutter_lints:
+ dependency: "direct dev"
+ description:
+ name: flutter_lints
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.4"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
+ hive:
+ dependency: transitive
+ description:
+ name: hive
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.4"
+ hydrated_bloc:
+ dependency: "direct main"
+ description:
+ name: hydrated_bloc
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "7.1.0"
+ lints:
+ dependency: transitive
+ description:
+ name: lints
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.1"
matcher:
dependency: transitive
description:
@@ -80,7 +150,14 @@ packages:
name: meta
url: "https://pub.dartlang.org"
source: hosted
- version: "1.3.0"
+ version: "1.7.0"
+ nested:
+ dependency: transitive
+ description:
+ name: nested
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.0"
path:
dependency: transitive
description:
@@ -88,6 +165,104 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
+ path_provider:
+ dependency: "direct main"
+ description:
+ name: path_provider
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.7"
+ path_provider_android:
+ dependency: transitive
+ description:
+ name: path_provider_android
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.9"
+ path_provider_ios:
+ dependency: transitive
+ description:
+ name: path_provider_ios
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.7"
+ path_provider_linux:
+ dependency: transitive
+ description:
+ name: path_provider_linux
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.2"
+ path_provider_macos:
+ dependency: transitive
+ description:
+ name: path_provider_macos
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.3"
+ path_provider_platform_interface:
+ dependency: transitive
+ description:
+ name: path_provider_platform_interface
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.1"
+ path_provider_windows:
+ dependency: transitive
+ description:
+ name: path_provider_windows
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.4"
+ petitparser:
+ dependency: transitive
+ description:
+ name: petitparser
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "4.4.0"
+ platform:
+ dependency: transitive
+ description:
+ name: platform
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.0.2"
+ plugin_platform_interface:
+ dependency: transitive
+ description:
+ name: plugin_platform_interface
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.2"
+ process:
+ dependency: transitive
+ description:
+ name: process
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "4.2.4"
+ provider:
+ dependency: transitive
+ description:
+ name: provider
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "6.0.1"
+ rational:
+ dependency: transitive
+ description:
+ name: rational
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.2.1"
+ sizer:
+ dependency: "direct main"
+ description:
+ name: sizer
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.15"
sky_engine:
dependency: transitive
description: flutter
@@ -121,6 +296,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
+ synchronized:
+ dependency: transitive
+ description:
+ name: synchronized
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.0.0"
term_glyph:
dependency: transitive
description:
@@ -134,7 +316,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
- version: "0.2.19"
+ version: "0.4.2"
typed_data:
dependency: transitive
description:
@@ -142,6 +324,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
+ universal_io:
+ dependency: transitive
+ description:
+ name: universal_io
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.4"
vector_math:
dependency: transitive
description:
@@ -149,5 +338,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
+ win32:
+ dependency: transitive
+ description:
+ name: win32
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.3.1"
+ xdg_directories:
+ dependency: transitive
+ description:
+ name: xdg_directories
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.2.0"
sdks:
- dart: ">=2.12.0-0.0 <3.0.0"
+ dart: ">=2.14.0 <3.0.0"
+ flutter: ">=2.5.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 9eddb09..bdf23c1 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,8 +1,8 @@
-name: calc_challenge
-description: A simple calculator.
+name: cal
+description: A new Flutter project.
# The following line prevents the package from being accidentally published to
-# pub.dev using `pub publish`. This is preferred for private packages.
+# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
@@ -18,8 +18,14 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
- sdk: ">=2.7.0 <3.0.0"
+ sdk: ">=2.12.0 <3.0.0"
+# Dependencies specify other packages that your package needs in order to work.
+# To automatically upgrade your package dependencies to the latest versions
+# consider running `flutter pub upgrade --major-versions`. Alternatively,
+# dependencies can be manually updated by changing the version numbers below to
+# the latest version available on pub.dev. To see which dependencies have newer
+# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
@@ -27,12 +33,24 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
- cupertino_icons: ^1.0.1
-
+ cupertino_icons: ^1.0.2
+ sizer: ^2.0.15
+ flutter_bloc: ^7.3.0
+ expression_language: ^1.0.1
+ hydrated_bloc: ^7.0.0
+ path_provider: ^2.0.7
+
dev_dependencies:
flutter_test:
sdk: flutter
+ # The "flutter_lints" package below contains a set of recommended lints to
+ # encourage good coding practices. The lint set provided by the package is
+ # activated in the `analysis_options.yaml` file located at the root of your
+ # package. See that file for information about deactivating specific lint
+ # rules and activating additional ones.
+ flutter_lints: ^1.0.0
+
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec