userjot_flutter 0.0.1
userjot_flutter: ^0.0.1 copied to clipboard
A Flutter package that ports the Swift UserJot SDK functionality for both Android and iOS.
import 'package:flutter/material.dart';
import 'package:userjot_flutter/userjot_flutter.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize UserJot with your project ID
// Replace 'your-project-id' with your actual UserJot project ID
await UserJot.setup('your-project-id');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'UserJot Flutter Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const UserJotExamplePage(),
);
}
}
class UserJotExamplePage extends StatefulWidget {
const UserJotExamplePage({super.key});
@override
State<UserJotExamplePage> createState() => _UserJotExamplePageState();
}
class _UserJotExamplePageState extends State<UserJotExamplePage> {
final TextEditingController _projectIdController = TextEditingController(text: 'your-project-id');
final TextEditingController _userIdController = TextEditingController(text: 'user123');
final TextEditingController _emailController = TextEditingController(text: 'user@example.com');
final TextEditingController _firstNameController = TextEditingController(text: 'John');
final TextEditingController _lastNameController = TextEditingController(text: 'Doe');
final TextEditingController _boardController = TextEditingController();
bool _isIdentified = false;
PresentationStyle _selectedStyle = PresentationStyle.sheet;
@override
void dispose() {
_projectIdController.dispose();
_userIdController.dispose();
_emailController.dispose();
_firstNameController.dispose();
_lastNameController.dispose();
_boardController.dispose();
super.dispose();
}
Future<void> _setupUserJot() async {
final projectId = _projectIdController.text.trim();
if (projectId.isEmpty) {
_showSnackBar('Please enter a project ID');
return;
}
try {
await UserJot.setup(projectId);
_showSnackBar('UserJot setup successful!');
} catch (e) {
_showSnackBar('Setup failed: $e');
}
}
void _identifyUser() {
final userId = _userIdController.text.trim();
if (userId.isEmpty) {
_showSnackBar('Please enter a user ID');
return;
}
UserJot.identify(
userId: userId,
email: _emailController.text.trim().isEmpty ? null : _emailController.text.trim(),
firstName: _firstNameController.text.trim().isEmpty ? null : _firstNameController.text.trim(),
lastName: _lastNameController.text.trim().isEmpty ? null : _lastNameController.text.trim(),
);
setState(() {
_isIdentified = true;
});
_showSnackBar('User identified: $userId');
}
void _logout() {
UserJot.logout();
setState(() {
_isIdentified = false;
});
_showSnackBar('User logged out');
}
void _showSnackBar(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('UserJot Flutter Example'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Setup Section
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Setup',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
TextField(
controller: _projectIdController,
decoration: const InputDecoration(
labelText: 'Project ID',
border: OutlineInputBorder(),
hintText: 'Enter your UserJot project ID',
),
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: _setupUserJot,
child: const Text('Setup UserJot'),
),
],
),
),
),
const SizedBox(height: 16),
// User Identification Section
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'User Identification',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
if (_isIdentified)
Chip(
label: const Text('Identified'),
backgroundColor: Colors.green[100],
),
],
),
const SizedBox(height: 8),
TextField(
controller: _userIdController,
decoration: const InputDecoration(
labelText: 'User ID *',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 8),
TextField(
controller: _emailController,
decoration: const InputDecoration(
labelText: 'Email',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 8),
TextField(
controller: _firstNameController,
decoration: const InputDecoration(
labelText: 'First Name',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 8),
TextField(
controller: _lastNameController,
decoration: const InputDecoration(
labelText: 'Last Name',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: _identifyUser,
child: const Text('Identify User'),
),
),
if (_isIdentified) ...[
const SizedBox(width: 8),
Expanded(
child: OutlinedButton(
onPressed: _logout,
child: const Text('Logout'),
),
),
],
],
),
],
),
),
),
const SizedBox(height: 16),
// Presentation Style Section
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Presentation Style',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
SegmentedButton<PresentationStyle>(
segments: const [
ButtonSegment(
value: PresentationStyle.sheet,
label: Text('Sheet'),
),
ButtonSegment(
value: PresentationStyle.mediumSheet,
label: Text('Medium Sheet'),
),
],
selected: {_selectedStyle},
onSelectionChanged: (Set<PresentationStyle> newSelection) {
setState(() {
_selectedStyle = newSelection.first;
});
},
),
],
),
),
),
const SizedBox(height: 16),
// Actions Section
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Actions',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
TextField(
controller: _boardController,
decoration: const InputDecoration(
labelText: 'Board Name (optional)',
border: OutlineInputBorder(),
hintText: 'Leave empty for default board',
),
),
const SizedBox(height: 16),
ElevatedButton.icon(
onPressed: () {
final board = _boardController.text.trim().isEmpty
? null
: _boardController.text.trim();
UserJot.showFeedback(
context,
board: board,
presentationStyle: _selectedStyle,
);
},
icon: const Icon(Icons.feedback),
label: const Text('Show Feedback'),
style: ElevatedButton.styleFrom(
minimumSize: const Size(double.infinity, 48),
),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: () {
UserJot.showRoadmap(
context,
presentationStyle: _selectedStyle,
);
},
icon: const Icon(Icons.map),
label: const Text('Show Roadmap'),
style: ElevatedButton.styleFrom(
minimumSize: const Size(double.infinity, 48),
),
),
const SizedBox(height: 8),
ElevatedButton.icon(
onPressed: () {
UserJot.showChangelog(
context,
presentationStyle: _selectedStyle,
);
},
icon: const Icon(Icons.update),
label: const Text('Show Changelog'),
style: ElevatedButton.styleFrom(
minimumSize: const Size(double.infinity, 48),
),
),
],
),
),
),
const SizedBox(height: 16),
// URL Generation Section
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'URL Generation',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
'Get URLs for custom WebView implementations:',
style: TextStyle(fontSize: 14),
),
const SizedBox(height: 8),
OutlinedButton.icon(
onPressed: () {
final url = UserJot.feedbackURL(
board: _boardController.text.trim().isEmpty
? null
: _boardController.text.trim(),
);
_showURLDialog('Feedback URL', url);
},
icon: const Icon(Icons.link),
label: const Text('Get Feedback URL'),
style: OutlinedButton.styleFrom(
minimumSize: const Size(double.infinity, 48),
),
),
const SizedBox(height: 8),
OutlinedButton.icon(
onPressed: () {
final url = UserJot.roadmapURL();
_showURLDialog('Roadmap URL', url);
},
icon: const Icon(Icons.link),
label: const Text('Get Roadmap URL'),
style: OutlinedButton.styleFrom(
minimumSize: const Size(double.infinity, 48),
),
),
const SizedBox(height: 8),
OutlinedButton.icon(
onPressed: () {
final url = UserJot.changelogURL();
_showURLDialog('Changelog URL', url);
},
icon: const Icon(Icons.link),
label: const Text('Get Changelog URL'),
style: OutlinedButton.styleFrom(
minimumSize: const Size(double.infinity, 48),
),
),
],
),
),
),
],
),
),
);
}
void _showURLDialog(String title, Uri? url) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(title),
content: SelectableText(
url?.toString() ?? 'URL not available. Make sure UserJot.setup() has been called.',
style: const TextStyle(fontSize: 12),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Close'),
),
],
),
);
}
}