Make a OKRs Tracker App with Flutter

What This App Does

A OKRs Tracker app serves a specific need in today's mobile-first world. Building one with Flutter means you ship to iOS, Android, and the web from a single codebase, cutting development time dramatically while keeping a native-quality experience.

Main Features

Feature Why It Matters
OKR Hierarchy Company → Department → Individual: align objectives across levels
Key Result Scoring Numeric progress (0–100%) or boolean KRs with manual/auto updates
Check-In Reminders Weekly prompt to update progress before team review
Confidence Ratings Traffic-light indicator (Red/Yellow/Green) for each objective's outlook

How to Make a OKRs Tracker App with Flutter

OKR Hierarchy

class Objective {
  final String id, title;
  double progress; // 0–100
  final String level; // company, department, individual
  final List keyResults;
  final List children;

  Objective({required this.id, required this.title, this.progress = 0,
    required this.level, this.keyResults = const [], this.children = const []});
}

class KeyResult {
  String title;
  double current, target;
  bool isBoolean;

  KeyResult({required this.title, this.current = 0, this.target = 1, this.isBoolean = false});

  double get progressPercent => isBoolean ? (current >= target ? 100 : 0) : (current / target * 100).clamp(0, 100);
}

class OkrTreeWidget extends StatelessWidget {
  final Objective objective;
  const OkrTreeWidget({super.key, required this.objective});

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(8),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(children: [
              _confidenceDot(objective.progress),
              const SizedBox(width: 8),
              Text(objective.title, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
              const Spacer(),
              Text('\${objective.progress.toStringAsFixed(0)}%', style: TextStyle(
                fontWeight: FontWeight.bold, color: _progressColor(objective.progress))),
            ]),
            const SizedBox(height: 8),
            ClipRRect(
              borderRadius: BorderRadius.circular(4),
              child: LinearProgressIndicator(
                value: objective.progress / 100,
                minHeight: 8,
                backgroundColor: Colors.grey.shade200,
              ),
            ),
            if (objective.keyResults.isNotEmpty) ...[
              const SizedBox(height: 12),
              ...objective.keyResults.map((kr) => Padding(
                padding: const EdgeInsets.only(left: 16, top: 4),
                child: Row(children: [
                  Text('• \${kr.title}', style: TextStyle(color: Colors.grey.shade600)),
                  const Spacer(),
                  Text('\${kr.current.toStringAsFixed(1)} / \${kr.target.toStringAsFixed(1)}'),
                ]),
              )),
            ],
            if (objective.children.isNotEmpty)
              ...objective.children.map((child) => OkrTreeWidget(objective: child)),
          ],
        ),
      ),
    );
  }

  Widget _confidenceDot(double progress) {
    final color = progress < 40 ? Colors.red : (progress < 70 ? Colors.orange : Colors.green);
    return Container(width: 12, height: 12, decoration: BoxDecoration(shape: BoxShape.circle, color: color));
  }

  Color _progressColor(double p) => p < 40 ? Colors.red : (p < 70 ? Colors.orange : Colors.green);
}

Recommended Libraries

Package Purpose
fl_chart Progress bars and radar charts
flutter_local_notifications Weekly check-in reminders

UI & UX Suggestions

Use a white cards, red/yellow/green confidence dots, clean sans-serif colour palette to match the app's purpose. Keep the navigation simple — a bottom nav bar or a single-scroll layout works best for this type of app. Make sure every interaction provides haptic or visual feedback so the app feels responsive and polished.