claform_sdk_flutter 1.1.1
claform_sdk_flutter: ^1.1.1 copied to clipboard
Flutter SDK for Claform surveys: 36 question types, content blocks, theming, offline support, and quiz scoring in a pure-Dart survey experience.
claform_sdk_flutter #
Flutter SDK for Claform. Provides a complete survey-taking experience with 36 question types, 6 content blocks, Material 3 theming, offline support, quiz scoring, and full backend API integration.
Pure Dart + Flutter implementation -- no TypeScript bridge or WebView. All engines (logic, validation, piping, quiz, randomization, theming, conflict resolution, A/B testing) are re-implemented natively in Dart.
Features #
- 36 question type widgets -- native Flutter implementations with Material 3 design
- 6 content blocks -- headings, text, images, video embeds, dividers, and spacers
- Provider-based state management -- SurveyNotifier (ChangeNotifier) wrapping SurveySDK
- SurveyScreen -- drop-in widget for a complete survey experience
- Swipe navigation -- gesture-based page transitions
- Animated transitions -- page transitions, validation shake animations
- Material 3 theming -- full theme resolution from survey config with Material 3 mapping
- Offline mode -- queue responses, sync when online, conflict resolution
- Quiz mode -- timer, hints, instant feedback, results screen
- Accessibility -- semantics labels, screen reader support
- Platform adapters -- SharedPreferences storage, Dio HTTP client, connectivity
- i18n -- multi-language surveys, RTL support
- Backend API integration -- full API client with retry and backoff
Requirements #
- Flutter >= 3.10.0
- Dart >= 3.0.0
Installation #
Add to your pubspec.yaml:
dependencies:
claform_sdk_flutter: ^1.0.0
Then run:
flutter pub get
Dependencies #
The SDK depends on:
| Package | Version | Purpose |
|---|---|---|
provider |
^6.1.1 | State management |
dio |
^5.4.0 | HTTP client |
shared_preferences |
^2.2.2 | Persistent storage |
uuid |
^4.2.1 | Session ID generation |
intl |
^0.19.0 | i18n and formatting |
collection |
^1.18.0 | Collection utilities |
file_picker |
^6.1.1 | File upload questions |
image_picker |
^1.0.7 | Photo upload questions |
signature |
^5.4.1 | Signature questions |
confetti |
^0.7.0 | Quiz celebration effects |
Quick Start #
import 'package:flutter/material.dart';
import 'package:claform_sdk_flutter/survey_sdk.dart';
class SurveyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SurveyScreen(
config: SurveySDKConfig(
apiUrl: 'https://api.example.com/api/v1',
shareId: 'abc123',
),
onComplete: (response) => print('Done! $response'),
onError: (error) => print('Error: $error'),
),
);
}
}
With Provider (Custom Layout) #
import 'package:provider/provider.dart';
import 'package:claform_sdk_flutter/survey_sdk.dart';
class CustomSurveyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => SurveyNotifier(
config: SurveySDKConfig(
apiUrl: 'https://api.example.com/api/v1',
shareId: 'abc123',
offlineEnabled: true,
storageAdapter: SharedPrefsStorageAdapter(),
),
),
child: Consumer<SurveyNotifier>(
builder: (context, notifier, _) {
if (notifier.phase == SurveyPhase.loading) {
return const LoadingScreen();
}
if (notifier.phase == SurveyPhase.error) {
return ErrorScreen(error: notifier.error);
}
if (notifier.phase == SurveyPhase.completed) {
return const ThankYouScreen();
}
return Column(
children: [
ProgressBar(progress: notifier.progress),
Expanded(
child: SurveyPageRenderer(
page: notifier.currentPage!,
answers: notifier.answers,
onAnswer: notifier.setAnswer,
),
),
NavigationButtons(
canGoNext: notifier.canGoNext,
canGoPrevious: notifier.canGoPrevious,
isLastPage: notifier.isLastPage,
onNext: notifier.nextPage,
onPrevious: notifier.previousPage,
onSubmit: notifier.submit,
),
],
);
},
),
);
}
}
State Management #
The SDK uses the Provider pattern with SurveyNotifier, a ChangeNotifier that wraps the core SurveySDK and subscribes to 12 EventBus events for reactive state updates.
SurveyNotifier #
| Property | Type | Description |
|---|---|---|
survey |
Survey? |
The loaded survey |
phase |
SurveyPhase |
Current lifecycle phase |
currentPage |
Page? |
Current page |
currentPageIndex |
int |
Current page index |
progress |
ProgressInfo |
Progress information |
answers |
Map<String, ResponseValue> |
All current answers |
validationErrors |
Map<String, List<String>> |
Validation errors |
visibleQuestionIds |
Set<String> |
IDs of visible questions |
isOnline |
bool |
Network status |
error |
SDKError? |
Current error |
canGoNext |
bool |
Whether next page is available |
canGoPrevious |
bool |
Whether previous page is available |
isLastPage |
bool |
Whether on last page |
| Method | Description |
|---|---|
loadSurvey() |
Load survey from API |
setAnswer(questionId, value) |
Set an answer |
clearAnswer(questionId) |
Clear an answer |
nextPage() |
Navigate forward |
previousPage() |
Navigate backward |
goToPage(index) |
Jump to page |
validateCurrentPage() |
Validate current page |
submit() |
Submit the response |
resume([sessionId]) |
Resume a saved session |
Widget Catalog #
Screens #
| Widget | Description |
|---|---|
SurveyScreen |
Full survey experience with all lifecycle phases |
LoadingScreen |
Loading state with indicator |
ErrorScreen |
Error state with retry |
ThankYouScreen |
Completion screen |
QuizResultScreen |
Quiz results display |
Navigation #
| Widget | Description |
|---|---|
SurveyPageRenderer |
Renders the current page with questions |
NavigationButtons |
Next/Previous/Submit buttons |
ProgressBar |
Survey progress indicator |
SwipeNavigator |
Gesture-based page navigation |
PageTransition |
Animated page transitions |
Question Types (36) #
All question widgets accept QuestionInputProps and are rendered automatically by QuestionRenderer.
Text: TextShortInput, TextLongInput
Choice: SingleChoiceInput, MultiChoiceInput, DropdownInput, ImageChoiceInput, ChoiceOption
Rating: RatingScaleInput, StarRatingInput, NPSInput, SliderInput, EmojiRatingInput, SemanticDifferentialInput, OpinionScaleInput
Boolean: YesNoInput
Date/Time: DateInput, DateTimeInput, TimeInput
Contact: EmailInput, PhoneInput, NumberInput, WebsiteUrlInput
Location: LocationInput
Advanced: RankingInput, MatrixSingleInput, MatrixMultiInput, FileUploadInput, PhotoUploadInput, SignatureInput, AddressInput, NameInput, ImageHeatmapInput, RepeatingGroupInput
Special: ConstantSumInput, MaxDiffInput, CardSortInput, PriceSensitivityInput
Content Blocks (6) #
Non-input display elements, rendered inline in page order and skipped by validation, progress, and answers.
| Widget | Description |
|---|---|
HeadingBlock |
Section heading (h1/h2/h3) |
TextBlock |
Rich text / paragraph content |
ImageBlock |
Image with caption and optional link |
VideoEmbedBlock |
Video (YouTube/Vimeo/Loom/custom) |
DividerBlock |
Horizontal rule |
SpacerBlock |
Vertical spacing |
Action elements (redirect, email, webhook, calculate, score display, payment, integration) are recognized by the SDK but execute server-side and are not rendered.
Quiz #
| Widget | Description |
|---|---|
QuizTimer |
Countdown timer display |
QuizHint |
Hint display for quiz questions |
QuizFeedback |
Immediate answer feedback |
Validation #
| Widget | Description |
|---|---|
ValidationError |
Error message display |
ShakeAnimation |
Shake effect for invalid fields |
ScrollToError |
Auto-scroll to first error |
Engines #
All engines are re-implemented in pure Dart:
| Engine | Description |
|---|---|
LogicEngine |
Conditional logic evaluation (17 operators) |
ValidationEngine |
Answer validation for all question types |
PipingEngine |
Answer piping into question text |
QuizEngine |
Quiz scoring (8 strategies) |
RandomizationEngine |
Deterministic option shuffling (Mulberry32 PRNG) |
ThemeEngine |
Theme resolution with Material 3 mapping |
ConflictEngine |
Offline sync conflict resolution |
ABTestingEngine |
A/B test variant assignment |
Services #
| Service | Description |
|---|---|
ApiClient |
HTTP client (Dio-based) with retry and backoff |
SessionManager |
Local session persistence and auto-save |
OfflineManager |
Response queuing and sync orchestration |
I18nManager |
Locale management and RTL detection |
DeepLinkParser |
Parse survey deep links |
PackageManager |
Offline survey package management |
MediaCache |
Media asset caching |
AnalyticsTracker |
Event tracking |
PaymentHandler |
Payment question processing |
Adapters #
| Adapter | Interface | Implementation | Description |
|---|---|---|---|
| Storage | StorageAdapter |
SharedPrefsStorageAdapter |
Persistent key-value storage |
| Network | NetworkAdapter |
DioNetworkAdapter |
HTTP client |
| Connectivity | ConnectivityAdapter |
-- | Network monitoring |
| Background Sync | BackgroundSyncAdapter |
-- | Background task scheduling |
| Encryption | EncryptionAdapter |
-- | Data encryption |
| Geolocation | GeolocationAdapter |
-- | GPS location |
| Biometric | BiometricAdapter |
-- | Biometric auth |
| Push Notifications | PushNotificationAdapter |
-- | Push delivery |
| Payment | PaymentAdapter |
-- | Payment processing |
| Analytics | AnalyticsAdapter |
-- | Analytics output |
Theming #
The SDK maps survey theme settings to Material 3 automatically. Override via config:
SurveyScreen(
config: SurveySDKConfig(
apiUrl: 'https://api.example.com/api/v1',
shareId: 'abc123',
themeOverrides: ThemeSettings(
colors: ThemeColors(
primary: '#6200EE',
background: '#FFFFFF',
text: '#212121',
),
typography: ThemeTypography(
fontFamily: 'Roboto',
),
),
),
)
Access theme values in custom widgets:
final theme = SurveyTheme.of(context);
Container(
color: theme.colors.background,
padding: EdgeInsets.all(theme.spacing.md),
child: Text(
'Content',
style: TextStyle(
color: theme.colors.text,
fontFamily: theme.fonts.body,
),
),
)
Theme Utilities #
import 'package:claform_sdk_flutter/survey_sdk.dart';
final color = ColorUtils.fromHex('#6200EE');
final lighter = ColorUtils.lighten(color, 0.2);
final darker = ColorUtils.darken(color, 0.1);
Offline Mode #
SurveyScreen(
config: SurveySDKConfig(
apiUrl: 'https://api.example.com/api/v1',
surveyId: 'survey-123',
offlineEnabled: true,
storageAdapter: SharedPrefsStorageAdapter(),
conflictStrategy: ConflictStrategy.clientWins,
),
)
The SDK automatically:
- Caches the survey definition for offline access
- Queues responses when offline
- Syncs queued responses when connectivity is restored
- Detects and resolves conflicts using the configured strategy
Platform-Specific Setup #
iOS #
Add to ios/Runner/Info.plist if using location questions:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This survey requires your location.</string>
Add for camera/photo access:
<key>NSCameraUsageDescription</key>
<string>This survey requires camera access for photo questions.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This survey requires photo library access.</string>
Android #
Add to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
License #
MIT