A modern, feature-rich calculator application built with Flutter. This app includes a clean UI, dark/light mode support, calculation history, and smooth animations.
- Basic Arithmetic Operations: Addition, subtraction, multiplication, and division
- Advanced Functions: Percentage calculations, sign toggling
- Dark/Light Mode: Toggle between themes
- Calculation History: View and manage past calculations
- Persistent Storage: History saved permanently on device
- Custom App Icon: Branded launcher icon for professional appearance
- Modern UI: Clean, minimalist design with smooth animations
- Swipe to Delete: Remove individual history entries with a swipe gesture
The app uses the Provider pattern for state management, separating business logic from UI components.
- ThemeProvider - Manages theme state (dark/light mode)
- HistoryManager - Manages calculation history state
- CalculatorLogic - Manages calculator computation state
- Purpose: Root widget that provides Material Design styling and navigation
- Usage in App: Configured with custom light and dark themes, sets up the home screen
- Location:
lib/main.dart - Key Properties:
theme: Light theme configurationdarkTheme: Dark theme configurationthemeMode: Current active theme mode from ThemeProvider
- Purpose: Allows multiple providers to be injected into the widget tree simultaneously
- Usage in App: Provides both ThemeProvider and HistoryManager to all child widgets
- Location:
lib/main.dart - Why We Use It: Enables multiple state management objects to be accessible throughout the app
- Purpose: Creates and provides a ChangeNotifier to descendant widgets
- Usage in App:
- Creates ThemeProvider instance for theme management
- Creates HistoryManager instance for history management
- Location:
lib/main.dart
- Purpose: Rebuilds when the provider's data changes
- Usage in App: Listens to ThemeProvider changes to rebuild the MaterialApp with updated theme
- Location:
lib/main.dart
- Purpose: Provides basic Material Design layout structure
- Usage in App:
- Main container for the calculator screen (
home.dart) - Main container for the history screen (
history_screen.dart)
- Main container for the calculator screen (
- Key Properties Used:
backgroundColor: Sets the background color based on themebody: Contains the main contentappBar: Top navigation bar (used in history screen)
- Purpose: Ensures content is displayed within safe boundaries (avoiding notches, status bars)
- Usage in App: Wraps the entire calculator interface to prevent overlap with system UI
- Location:
lib/home.dart
- Purpose: Arranges children vertically
- Usage in App:
- Main layout structure in calculator (top bar, display, button grid)
- Display area (expression and result)
- Button grid rows
- Empty state in history screen
- History card content
- Key Properties Used:
mainAxisAlignment: Controls vertical alignmentcrossAxisAlignment: Controls horizontal alignmentchildren: List of child widgets
- Purpose: Arranges children horizontally
- Usage in App:
- Top bar (dark mode toggle and history button)
- Each row of calculator buttons
- Content inside toggle/history buttons
- Key Properties Used:
mainAxisAlignment: Controls horizontal spacingchildren: List of child widgets
- Purpose: Expands a child to fill available space in a Row/Column
- Usage in App:
- Calculator display area (flex: 2)
- Button grid area (flex: 3)
- Individual calculator buttons to ensure equal sizing
- Key Properties Used:
flex: Relative size compared to other Expanded widgetschild: Widget to expand
- Purpose: General-purpose box widget for styling and positioning
- Usage in App:
- Dark mode toggle button wrapper
- History button wrapper
- Display area wrapper
- Button grid wrapper
- Individual button containers
- History card containers
- Dismissible background
- Key Properties Used:
padding: Inner spacingmargin: Outer spacingdecoration: Border, color, radius stylingalignment: Child alignmentwidth/height: Size constraints
- Purpose: Adds padding around a widget
- Usage in App: Top bar padding, button grid padding
- Location: Throughout the app for spacing
- Purpose: Fixed-size box, often used for spacing
- Usage in App: Vertical spacing between display elements, horizontal spacing in buttons
- Common Sizes: 8px, 16px for consistent spacing
- Purpose: Detects gestures like taps, swipes, long presses
- Usage in App:
- Dark mode toggle button
- History navigation button
- Key Properties Used:
onTap: Callback when tappedchild: Widget to make interactive
- Purpose:
Material: Provides Material Design surfaceInkWell: Adds touch ripple effects
- Usage in App: Calculator buttons for visual feedback on press
- Key Properties Used:
- Material:
color,borderRadius - InkWell:
onTap,borderRadius
- Material:
- Why We Use It: Creates professional Material Design ripple animations
- Purpose: Clickable icon with Material Design ripple
- Usage in App: Back button in history screen AppBar
- Key Properties Used:
icon: The icon to displayonPressed: Tap callback
- Purpose: Flat button with text
- Usage in App:
- "Clear All" button in history screen
- Dialog action buttons (Cancel, Clear)
- Key Properties Used:
onPressed: Tap callbackchild: Button content (usually Text)
- Purpose: Enables swipe-to-dismiss gesture
- Usage in App: History entries can be swiped away to delete
- Location:
lib/history_screen.dart - Key Properties Used:
key: Unique identifier for each itemdirection: Swipe direction (endToStart = right to left)background: Widget shown when swipingonDismissed: Callback when dismissed
- Purpose: Displays text with styling
- Usage in App:
- Display value in calculator
- Expression display
- Button labels
- History entries
- Timestamps
- Empty state messages
- Key Properties Used:
style: TextStyle for font size, color, weightmaxLines: Maximum number of linesoverflow: How to handle overflow (ellipsis)
- Purpose: Displays Material Design icons
- Usage in App:
- Dark/light mode icons
- History icon
- Back arrow
- Delete icon in dismissible background
- Empty state icon
- Key Properties Used:
size: Icon sizecolor: Icon color
- Icons Used:
Icons.dark_mode/Icons.light_modeIcons.historyIcons.arrow_backIcons.delete
- Purpose: Top navigation bar with title and actions
- Usage in App: History screen navigation
- Location:
lib/history_screen.dart - Key Properties Used:
backgroundColor: Matches screen backgroundelevation: Shadow depth (0 for flat)leading: Back buttontitle: "History" textactions: "Clear All" button
- Purpose: Rebuilds when a Listenable (like ChangeNotifier) changes
- Usage in App:
- Rebuilds expression display when calculator state changes
- Rebuilds main display value when calculator state changes
- Location:
lib/home.dart - Key Properties Used:
listenable: The ChangeNotifier to listen to (CalculatorLogic)builder: Function that builds the widget
- Purpose: Efficiently builds scrollable lists
- Usage in App: Displays calculation history with lazy loading
- Location:
lib/history_screen.dart - Key Properties Used:
padding: List paddingitemCount: Number of itemsitemBuilder: Function to build each item
- Purpose: Shows a modal dialog
- Usage in App: Confirmation dialog before clearing all history
- Location:
lib/history_screen.dart - Key Properties Used:
backgroundColor: Dialog background colortitle: Dialog titlecontent: Dialog messageactions: Dialog buttons
- Purpose: Manages app navigation and routing
- Usage in App:
Navigator.push: Navigate to history screenNavigator.pop: Return to calculator screen, close dialogs
- Locations:
lib/home.dart,lib/history_screen.dart
- Purpose: Accesses a provider from the widget tree
- Usage in App:
- Access ThemeProvider for theme state
- Access HistoryManager for calculation history
- Key Properties Used:
listen: Whether to rebuild when provider changes (true/false)
- Purpose: Provides visual decoration for containers
- Usage in App:
- Button backgrounds with rounded corners
- Card backgrounds for history entries
- Dismissible background
- Key Properties Used:
color: Background colorborderRadius: Rounded cornersborder: Border styling (if needed)
- Purpose: Defines rounded corners
- Usage in App: All buttons and cards use
BorderRadius.circular(16)orBorderRadius.circular(20)for consistent rounded corners
- Purpose: Defines text appearance
- Usage in App: Font size, color, weight for all text elements
- Key Properties Used:
fontSize: Text size (11-64px range)color: Text colorfontWeight: Font weight (w300-w600)
- Purpose: Handles all calculator computation and state
- File:
lib/calculator_logic.dart - Key Methods:
onNumberPressed(): Handle digit inputonOperationPressed(): Handle operation (+, -, ×, ÷)onEqualsPressed(): Perform calculationonClearPressed(): Reset calculatoronBackspacePressed(): Delete last digitonPercentPressed(): Convert to percentageonDecimalPressed(): Add decimal point
- Purpose: Manages app theme state
- File:
lib/theme_provider.dart - Key Methods:
toggleTheme(): Switch between light/dark modesetThemeMode(): Set specific theme
- Static Properties:
lightTheme: Light theme configurationdarkTheme: Dark theme configuration
- Purpose: Manages calculation history with persistent storage
- File:
lib/history_manager.dart - Key Methods:
loadHistory(): Load saved history from device storage (async)addCalculation(): Add new calculation and save to storage (async)clearHistory(): Remove all history and update storage (async)removeAt(): Remove specific entry and save changes (async)_saveHistory(): Private method to persist history to SharedPreferences
- Properties:
history: List of CalculationHistory objectsisEmpty: Check if history is emptycount: Number of history entries
- Storage Implementation:
- Uses SharedPreferences for persistent local storage
- Stores history as JSON string with key
'calculation_history' - Automatically saves after every modification (add/remove/clear)
- Purpose: Represents a single calculation entry
- File:
lib/history_manager.dart - Properties:
calculation: The expression (e.g., "15 + 23")result: The answer (e.g., "38")timestamp: When it was calculated
- Factory Methods:
fromCalculationString(): Parse calculation string into modelfromJson(): Deserialize from JSON map (for loading from storage)
- Serialization Methods:
toJson(): Convert to JSON map (for saving to storage)
The app uses SharedPreferences to store calculation history permanently on the user's device. Here's how it works:
Each CalculationHistory object is converted to JSON format:
Map<String, dynamic> toJson() {
return {
'calculation': calculation,
'result': result,
'timestamp': timestamp.toIso8601String(),
};
}When history changes (add/remove/clear), the entire history list is:
- Converted to a list of JSON maps
- Encoded as a JSON string
- Saved to SharedPreferences with key
'calculation_history'
Future<void> _saveHistory() async {
final prefs = await SharedPreferences.getInstance();
final jsonList = _history.map((item) => item.toJson()).toList();
final jsonString = jsonEncode(jsonList);
await prefs.setString(_historyKey, jsonString);
}When the app starts:
- SharedPreferences retrieves the JSON string
- JSON is decoded into a list of maps
- Each map is converted back to
CalculationHistoryobjects - The history list is populated
Future<void> loadHistory() async {
final prefs = await SharedPreferences.getInstance();
final historyJson = prefs.getString(_historyKey);
if (historyJson != null && historyJson.isNotEmpty) {
final decoded = jsonDecode(historyJson) as List<dynamic>;
_history.addAll(
decoded.map((item) => CalculationHistory.fromJson(item))
);
notifyListeners();
}
}In main.dart, the HistoryManager is created and loads history immediately:
ChangeNotifierProvider(
create: (_) {
final historyManager = HistoryManager();
historyManager.loadHistory(); // Loads saved history on app start
return historyManager;
},
)SharedPreferences stores data in platform-specific locations:
- Android: XML file in app's data directory
- iOS: NSUserDefaults
- Web: Browser's LocalStorage
- Windows/Linux/macOS: JSON file in app's data directory
- ✅ Persistent: History survives app restarts and device reboots
- ✅ Automatic: No manual save button needed - saves after every change
- ✅ Cross-platform: Works on all Flutter platforms
- ✅ Reliable: Uses native platform storage APIs
- ✅ Efficient: Only saves when needed, loads once at startup
The app uses a custom launcher icon instead of the default Flutter logo, providing a professional branded appearance on the device home screen.
1. Icon Asset Preparation
- Created/obtained custom icon image:
nextgenicon.jpeg - Placed in
assets/icon/directory - Recommended size: 1024x1024 pixels for best quality
2. Package Configuration
Added flutter_launcher_icons to pubspec.yaml:
dev_dependencies:
flutter_launcher_icons: ^0.13.13. Icon Configuration
Added icon generation settings to pubspec.yaml:
flutter_launcher_icons:
android: true
ios: true
image_path: "assets/icon/nextgenicon.jpeg"4. Icon Generation Ran the icon generator command:
flutter pub get
dart run flutter_launcher_iconsThis automatically generated all required icon sizes:
- Android: mipmap-mdpi (48x48), hdpi (72x72), xhdpi (96x96), xxhdpi (144x144), xxxhdpi (192x192)
- iOS: App icon sets for all required sizes
5. Build Integration The generated icons are automatically included when building the app:
flutter build apk --release # For Android
flutter build ios --release # For iOS- flutter_launcher_icons reads the source image from
assets/icon/nextgenicon.jpeg - Automatically resizes it to all required dimensions for each platform
- Places the generated icons in the correct platform-specific directories:
- Android:
android/app/src/main/res/mipmap-*/ic_launcher.png - iOS:
ios/Runner/Assets.xcassets/AppIcon.appiconset/
- Android:
- Updates platform configuration files to reference the new icons
- The custom icon appears on the device home screen after installation
- ✅ Professional branding with custom app identity
- ✅ Automatic generation of all required sizes and formats
- ✅ Cross-platform support (Android, iOS, and more)
- ✅ No manual work resizing or placing icon files
- ✅ Consistent appearance across all device resolutions
The app displays as "NextGen Calculator" on the device instead of the default package name nextgen_calculator. This provides a professional, user-friendly name on the home screen and app drawer.
The app name is configured separately for each platform in their respective manifest files:
1. Android Configuration
Edit android/app/src/main/AndroidManifest.xml:
<application
android:label="NextGen Calculator"
...
>- The
android:labelattribute sets the app name displayed on Android devices - Changed from
"nextgen_calculator"to"NextGen Calculator" - This name appears in the app drawer, home screen, and recent apps list
2. iOS Configuration
Edit ios/Runner/Info.plist:
<key>CFBundleDisplayName</key>
<string>NextGen Calculator</string>
<key>CFBundleName</key>
<string>NextGen Calculator</string>CFBundleDisplayName: The user-visible name shown on the iOS home screenCFBundleName: The bundle name used by the system- Changed both from
"nextgen_calculator"to"NextGen Calculator"
3. Rebuild the App
After changing the manifest files, rebuild the app:
flutter build apk --release # For Android
flutter build ios --release # For iOS- Package name vs Display name: The package name in
pubspec.yaml(nextgen_calculator) remains unchanged and is used internally by Flutter and for app identification - Display name: The user-visible name in manifest files can be anything user-friendly
- Platform-specific: Each platform has its own configuration file for the app name
- Rebuild required: Changes only take effect after rebuilding and reinstalling the app
- ✅ Professional appearance with properly formatted app name
- ✅ User-friendly with spaces and proper capitalization
- ✅ Searchable in app stores and device search
- ✅ Consistent branding across all platforms
- Background:
Colors.white/#FFFFFF - Display Background:
Color(0xFFF1F2F3) - Button Background:
Color(0xFFF1F2F3) - Operation Buttons:
Color(0xFFE8E9EB)with blue text - Equals Button:
Color(0xFF4A90E2)(Blue) - Text:
Colors.black87
- Background:
Color(0xFF22252D) - Display Background:
Color(0xFF292D36) - Number Buttons:
Color(0xFF2C2F38) - Operation/Function Buttons:
Color(0xFF3D4451) - Equals Button:
Color(0xFF5AA9E6)(Bright Blue) - Text:
Colors.white
- Top Bar: Theme toggle and history navigation
- Display Area: Shows current expression and result
- Button Grid: 5x4 grid with numbers, operations, and functions
- Buttons:
- Numbers: 0-9
- Operations: +, −, ×, ÷
- Functions: C (Clear), +/− (Sign toggle), % (Percent), ⌫ (Backspace)
- Equals: = (Calculate)
- AppBar: Back button, title, and "Clear All" button
- Empty State: Shown when no calculations exist
- History List: Scrollable list of past calculations
- Each Entry Shows:
- Calculation expression
- Result
- Relative timestamp (e.g., "2h ago", "Yesterday")
- Interactions:
- Swipe left to delete individual entry
- Tap "Clear All" to delete all (with confirmation)
dependencies:
flutter:
sdk: flutter
provider: ^6.1.2 # State management
shared_preferences: ^2.2.2 # Local persistent storage
dev_dependencies:
flutter_launcher_icons: ^0.13.1 # App icon generator- Simple: Easy to understand and implement
- Efficient: Only rebuilds widgets that listen to changes
- Scalable: Works well for small to medium apps
- Recommended: Official Flutter team recommendation
- Persistent: Data survives app restarts and device reboots
- Simple API: Easy key-value storage for simple data structures
- Cross-platform: Works on Android, iOS, Web, and Desktop
- Lightweight: Perfect for storing small amounts of data like settings and history
- Automated: Generates all required icon sizes automatically
- Multi-platform: Creates icons for Android, iOS, and other platforms
- Time-saving: No need to manually resize icons for different densities
- Consistent: Ensures proper icon formatting across all devices
- Flutter SDK (latest stable version)
- Dart SDK
- Android Studio / VS Code with Flutter extensions
# Clone the repository
git clone <repository-url>
# Navigate to project directory
cd nextgen_calculator
# Install dependencies
flutter pub get
# Run the app
flutter run# Android
flutter build apk --release
# iOS
flutter build ios --release
# Web
flutter build weblib/
├── main.dart # App entry point, provider setup
├── home.dart # Main calculator screen
├── history_screen.dart # Calculation history screen
├── calculator_logic.dart # Calculator computation logic
├── theme_provider.dart # Theme management
└── history_manager.dart # History management & model
- State Management: Provider pattern with ChangeNotifier
- Persistent Storage: SharedPreferences for local data persistence
- Data Serialization: JSON encoding/decoding for storage
- Async Programming: Future-based async operations for storage I/O
- Asset Management: Custom app icons and resource bundling
- Build Automation: Automated icon generation with flutter_launcher_icons
- Platform Configuration: Android and iOS manifest files for app metadata
- Responsive Design: Flexible layouts with Expanded and Column/Row
- Theming: Dynamic theme switching with ThemeProvider
- Navigation: Screen transitions with Navigator
- Gestures: Dismissible for swipe-to-delete
- List Building: Efficient ListView.builder
- Dialogs: AlertDialog for confirmations
- Custom Widgets: Reusable button builder method
- Model Classes: Data encapsulation with CalculationHistory
- Separation of Concerns: UI, logic, and state management separated