added activities and conference type, get list dynamic, todo: year, month params and fix ui for list whit images.
This commit is contained in:
parent
19d2968b8c
commit
e9f834c267
|
|
@ -1,19 +1,26 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:lgcc/pages/conferences.dart';
|
import 'package:lgcc/pages/home.dart';
|
||||||
|
import 'package:lgcc/navigation_bar.dart';
|
||||||
|
// import 'package:lgcc/pages/items_list.dart';
|
||||||
|
|
||||||
Future main() async {
|
Future main() async {
|
||||||
await dotenv.load(fileName: ".env");
|
await dotenv.load(fileName: ".env");
|
||||||
runApp(MyApp());
|
runApp(MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatefulWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MyApp> createState() => _MyAppState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyAppState extends State<MyApp> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const MaterialApp(
|
return MaterialApp(
|
||||||
home: ConferencesPage(),
|
home: MainNavigationBar(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
class TranslationModel {
|
|
||||||
final int id;
|
|
||||||
final String language;
|
|
||||||
final String title;
|
|
||||||
final String? markdown;
|
|
||||||
|
|
||||||
TranslationModel({
|
|
||||||
required this.id,
|
|
||||||
required this.language,
|
|
||||||
required this.title,
|
|
||||||
this.markdown,
|
|
||||||
});
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return {
|
|
||||||
'id': id,
|
|
||||||
'language': language,
|
|
||||||
'title': title,
|
|
||||||
'markdown': markdown,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
factory TranslationModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
return TranslationModel(
|
|
||||||
id: json['id'] ?? 0,
|
|
||||||
language: json['language'] ?? '',
|
|
||||||
title: json['title'] ?? '',
|
|
||||||
markdown: json['markdown'] ?? '',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConferencesModel {
|
|
||||||
|
|
||||||
final int id;
|
|
||||||
final String title;
|
|
||||||
final DateTime date;
|
|
||||||
int activity;
|
|
||||||
int duration;
|
|
||||||
String place;
|
|
||||||
String city;
|
|
||||||
String state;
|
|
||||||
String country;
|
|
||||||
// List<String> type;
|
|
||||||
String thumbnail;
|
|
||||||
List<TranslationModel> translations;
|
|
||||||
|
|
||||||
ConferencesModel({
|
|
||||||
required this.id,
|
|
||||||
required this.title,
|
|
||||||
required this.date,
|
|
||||||
this.activity = 0,
|
|
||||||
this.duration = 0,
|
|
||||||
this.place = '',
|
|
||||||
this.city = '',
|
|
||||||
this.state = '',
|
|
||||||
this.country = '',
|
|
||||||
// this.type = const [],
|
|
||||||
this.thumbnail = '',
|
|
||||||
this.translations = const [],
|
|
||||||
});
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
return {
|
|
||||||
'id': id,
|
|
||||||
'title': title,
|
|
||||||
'date': date.toIso8601String(),
|
|
||||||
'activity': activity,
|
|
||||||
'duration': duration,
|
|
||||||
'place': place,
|
|
||||||
'city': city,
|
|
||||||
'state': state,
|
|
||||||
'country': country,
|
|
||||||
// 'type': type,
|
|
||||||
'thumbnail': thumbnail.toString(),
|
|
||||||
'translations': translations.toString() ,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
factory ConferencesModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
return ConferencesModel(
|
|
||||||
id: json['id'] ?? 0,
|
|
||||||
title: json['title'] ?? '',
|
|
||||||
date: json['date'] != null ? DateTime.parse(json['date'].toString()) : DateTime.now(),
|
|
||||||
activity: json['activity'] ?? 0,
|
|
||||||
duration: json['duration'] ?? 0,
|
|
||||||
place: json['place'] ?? '',
|
|
||||||
city: json['city'] ?? '',
|
|
||||||
state: json['state'] ?? '',
|
|
||||||
country: json['country'] ?? '',
|
|
||||||
// type: List<String>.from(json['type'] ?? []),
|
|
||||||
thumbnail: json['thumbnail'] ?? '',
|
|
||||||
translations: (json['translations'] as List<dynamic>?)
|
|
||||||
?.map((item) => TranslationModel.fromJson(item as Map<String, dynamic>))
|
|
||||||
.toList() ?? [],
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,216 @@
|
||||||
|
class TranslationModel {
|
||||||
|
final int id;
|
||||||
|
final String locale;
|
||||||
|
|
||||||
|
TranslationModel({required this.id, required this.locale});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {'id': id, 'language': locale};
|
||||||
|
}
|
||||||
|
|
||||||
|
factory TranslationModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return TranslationModel(id: json['id'] ?? 0, locale: json['locale'] ?? '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Files {
|
||||||
|
final String? youtube;
|
||||||
|
final String? video;
|
||||||
|
final String? audio;
|
||||||
|
final String? booklet;
|
||||||
|
final String? simple;
|
||||||
|
|
||||||
|
Files({this.youtube, this.video, this.audio, this.booklet, this.simple});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'youtube': youtube,
|
||||||
|
'video': video,
|
||||||
|
'audio': audio,
|
||||||
|
'booklet': booklet,
|
||||||
|
'simple': simple,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
factory Files.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Files(
|
||||||
|
youtube: json['youtube'] as String?,
|
||||||
|
video: json['video'] as String?,
|
||||||
|
audio: json['audio'] as String?,
|
||||||
|
booklet: json['booklet'] as String?,
|
||||||
|
simple: json['simple'] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DurationField {
|
||||||
|
final int duration;
|
||||||
|
|
||||||
|
DurationField({required this.duration});
|
||||||
|
|
||||||
|
factory DurationField.fromJson(Map<String, dynamic> json) {
|
||||||
|
// convert duration from string to int
|
||||||
|
final dynamic rawDuration = json['duration'];
|
||||||
|
final int parsedDuration = rawDuration is String
|
||||||
|
? int.tryParse(rawDuration) ?? 0
|
||||||
|
: rawDuration is int
|
||||||
|
? rawDuration
|
||||||
|
: 0;
|
||||||
|
return DurationField(duration: parsedDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemModel {
|
||||||
|
final String id;
|
||||||
|
final String title;
|
||||||
|
final DateTime date;
|
||||||
|
final String type;
|
||||||
|
final String? slug;
|
||||||
|
bool rm;
|
||||||
|
String biblestudy;
|
||||||
|
bool draft;
|
||||||
|
int timestamp;
|
||||||
|
String activity;
|
||||||
|
DurationField duration;
|
||||||
|
String place;
|
||||||
|
String city;
|
||||||
|
String state;
|
||||||
|
String country;
|
||||||
|
// List<String> type;
|
||||||
|
String thumbnail;
|
||||||
|
List<TranslationModel> translations;
|
||||||
|
Files files;
|
||||||
|
|
||||||
|
ItemModel({
|
||||||
|
required this.id,
|
||||||
|
required this.title,
|
||||||
|
required this.date,
|
||||||
|
this.type = '',
|
||||||
|
this.slug,
|
||||||
|
this.rm = false,
|
||||||
|
this.biblestudy = '',
|
||||||
|
this.draft = false,
|
||||||
|
this.timestamp = 0,
|
||||||
|
this.activity = '',
|
||||||
|
required this.duration,
|
||||||
|
this.place = '',
|
||||||
|
this.city = '',
|
||||||
|
this.state = '',
|
||||||
|
this.country = '',
|
||||||
|
// this.type = const [],
|
||||||
|
this.thumbnail = '',
|
||||||
|
this.translations = const [],
|
||||||
|
Files? files,
|
||||||
|
}) : files = files ?? Files();
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'id': id,
|
||||||
|
'title': title,
|
||||||
|
'date': date.toIso8601String(),
|
||||||
|
'type': type,
|
||||||
|
'slug': slug,
|
||||||
|
'rm': rm,
|
||||||
|
'biblestudy': biblestudy,
|
||||||
|
'draft': draft,
|
||||||
|
'timestamp': timestamp,
|
||||||
|
'activity': activity,
|
||||||
|
'duration': duration,
|
||||||
|
'place': place,
|
||||||
|
'city': city,
|
||||||
|
'state': state,
|
||||||
|
'country': country,
|
||||||
|
'thumbnail': thumbnail.toString(),
|
||||||
|
'translations': translations.toString(),
|
||||||
|
'files': files.toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
factory ItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return ItemModel(
|
||||||
|
id: json['id'] ?? '',
|
||||||
|
title: json['title'] ?? '',
|
||||||
|
date:
|
||||||
|
json['date'] != null
|
||||||
|
? DateTime.parse(json['date'].toString())
|
||||||
|
: DateTime.now(),
|
||||||
|
type: json['type'] ?? '',
|
||||||
|
slug: json['slug'],
|
||||||
|
rm: json['rm'] ?? false,
|
||||||
|
biblestudy: json['biblestudy'] ?? '',
|
||||||
|
draft: json['draft'] ?? false,
|
||||||
|
timestamp: json['timestamp'] ?? 0,
|
||||||
|
activity: json['activity'] ?? '',
|
||||||
|
duration: DurationField.fromJson({'duration': json['duration']}),
|
||||||
|
place: json['place'] ?? '',
|
||||||
|
city: json['city'] ?? '',
|
||||||
|
state: json['state'] ?? '',
|
||||||
|
country: json['country'] ?? '',
|
||||||
|
// type: List<String>.from(json['type'] ?? []),
|
||||||
|
thumbnail: json['thumbnail'] ?? '',
|
||||||
|
translations:
|
||||||
|
(json['translations'] as List<dynamic>?)
|
||||||
|
?.map(
|
||||||
|
(item) =>
|
||||||
|
TranslationModel.fromJson(item as Map<String, dynamic>),
|
||||||
|
)
|
||||||
|
.toList() ??
|
||||||
|
[],
|
||||||
|
files:
|
||||||
|
json['files'] != null
|
||||||
|
? (json['files'] is Map<String, dynamic>
|
||||||
|
? Files.fromJson(json['files'] as Map<String, dynamic>)
|
||||||
|
: Files())
|
||||||
|
: Files(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ResultModel {
|
||||||
|
final List<YearModel> years;
|
||||||
|
|
||||||
|
ResultModel({required this.years});
|
||||||
|
|
||||||
|
factory ResultModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return ResultModel(
|
||||||
|
years: (json['years'] as List)
|
||||||
|
.map((e) => YearModel.fromJson(e))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class YearModel {
|
||||||
|
final int year;
|
||||||
|
final int count;
|
||||||
|
final List<MonthModel> months;
|
||||||
|
|
||||||
|
YearModel({required this.year, required this.count, required this.months});
|
||||||
|
|
||||||
|
factory YearModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return YearModel(
|
||||||
|
year: json['year'],
|
||||||
|
count: json['count'],
|
||||||
|
months: (json['months'] as List)
|
||||||
|
.map((e) => MonthModel.fromJson(e))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MonthModel {
|
||||||
|
final String name;
|
||||||
|
final String month;
|
||||||
|
final int count;
|
||||||
|
|
||||||
|
MonthModel({required this.name, required this.month, required this.count});
|
||||||
|
|
||||||
|
factory MonthModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return MonthModel(
|
||||||
|
name: json['name'],
|
||||||
|
month: json['month'],
|
||||||
|
count: int.parse(json['count']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lgcc/pages/home.dart';
|
||||||
|
import 'package:lgcc/pages/items_list.dart';
|
||||||
|
|
||||||
|
class MainNavigationBar extends StatefulWidget {
|
||||||
|
@override _MainNavigationBarState createState() => _MainNavigationBarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MainNavigationBarState extends State<MainNavigationBar> {
|
||||||
|
int _currentIndex =0;
|
||||||
|
|
||||||
|
final List<Widget> _pages = [
|
||||||
|
HomePage(),
|
||||||
|
ItemsList(type: 'conferencias'),
|
||||||
|
ItemsList(type: 'actividades'),
|
||||||
|
];
|
||||||
|
|
||||||
|
void _onTabTapped(int index) {
|
||||||
|
setState(() {
|
||||||
|
_currentIndex = index;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: IndexedStack(
|
||||||
|
index: _currentIndex,
|
||||||
|
children: _pages,
|
||||||
|
),
|
||||||
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
|
currentIndex: _currentIndex,
|
||||||
|
onTap: _onTabTapped,
|
||||||
|
items: const [
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.home),
|
||||||
|
label: 'Inicio',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.list),
|
||||||
|
label: 'Conferencias',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.list),
|
||||||
|
label: 'Publicaciones',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_html/flutter_html.dart';
|
|
||||||
import 'package:lgcc/models/conferences_model.dart';
|
|
||||||
import 'package:lgcc/providers/directus_service.dart';
|
|
||||||
import 'package:lgcc/pages/detail_conference.dart';
|
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|
||||||
|
|
||||||
class ConferencesPage extends StatelessWidget {
|
|
||||||
final dynamic confereceDetail;
|
|
||||||
|
|
||||||
const ConferencesPage({super.key, this.confereceDetail});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('Conferencias'),
|
|
||||||
centerTitle: true,
|
|
||||||
backgroundColor: Color(0xFFE5EBFD),
|
|
||||||
),
|
|
||||||
body: _buildConferenceListView(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildConferenceListView() {
|
|
||||||
final DirectusService _directusService = DirectusService();
|
|
||||||
|
|
||||||
return FutureBuilder(
|
|
||||||
future: Future.wait([_directusService.getConferences()]),
|
|
||||||
builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {
|
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
||||||
return const Center(child: CircularProgressIndicator());
|
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
print('Error: ${snapshot.error}');
|
|
||||||
return Center(child: Text('Error: ${snapshot.error}'));
|
|
||||||
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
|
||||||
return const Center(child: Text('No conferences found.'));
|
|
||||||
} else {
|
|
||||||
List<ConferencesModel> conferences = List<ConferencesModel>.from(
|
|
||||||
snapshot.data![0],
|
|
||||||
);
|
|
||||||
return ListView.builder(
|
|
||||||
itemCount: conferences.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final conference = conferences[index];
|
|
||||||
String urlImage;
|
|
||||||
if (conference.thumbnail.isEmpty) {
|
|
||||||
urlImage =
|
|
||||||
'https://ik.imagekit.io/lgccc/tr:w-1920,f-auto/youtube_thumbnail_46396.png';
|
|
||||||
} else {
|
|
||||||
urlImage =
|
|
||||||
'https://directus.carpa.com/assets/${conference.thumbnail}?access_token=${dotenv.env['DIRECTUS_API_TOKEN']}';
|
|
||||||
}
|
|
||||||
return InkWell(
|
|
||||||
onTap: () => Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => DetailConference(conference: conference),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Card(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Image.network(
|
|
||||||
urlImage,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
width: double.infinity,
|
|
||||||
height: 200,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(conference.title, style: const TextStyle(fontSize: 18)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +1,36 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_html/flutter_html.dart';
|
import 'package:flutter_html/flutter_html.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'package:lgcc/models/conferences_model.dart';
|
import 'package:lgcc/models/item_model.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
class DetailConference extends StatelessWidget {
|
class DetailItem extends StatefulWidget {
|
||||||
final ConferencesModel conference;
|
final ItemModel items;
|
||||||
const DetailConference({super.key, required this.conference});
|
const DetailItem({super.key, required this.items});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DetailItem> createState() => _DetailItemState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DetailItemState extends State<DetailItem> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// Check if the conference has a thumbnail, if not use a default image
|
// Check if the conference has a thumbnail, if not use a default image
|
||||||
String urlImage;
|
// String urlImage;
|
||||||
if (conference.thumbnail.isEmpty) {
|
// if (widget.items.thumbnail.isEmpty) {
|
||||||
urlImage =
|
// urlImage =
|
||||||
'https://ik.imagekit.io/lgccc/tr:w-1920,f-auto/youtube_thumbnail_46396.png';
|
// 'https://ik.imagekit.io/lgccc/tr:w-1920,f-auto/youtube_thumbnail_46396.png';
|
||||||
} else {
|
// } else {
|
||||||
urlImage =
|
// urlImage =
|
||||||
'https://directus.carpa.com/assets/${conference.thumbnail}?access_token=${dotenv.env['DIRECTUS_API_TOKEN']}';
|
// 'https://actividadeswp.carpa.com/v5/uploads/?path=${widget.items.thumbnail}';
|
||||||
}
|
// }
|
||||||
|
|
||||||
final formattedDate = DateFormat.yMMMMEEEEd().format(conference.date);
|
final formattedDate = DateFormat.yMMMMEEEEd().format(widget.items.date);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Conferencias'),
|
title: Text(widget.items.title),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
backgroundColor: Color(0xFFE5EBFD),
|
backgroundColor: Color(0xFFE5EBFD),
|
||||||
),
|
),
|
||||||
|
|
@ -38,10 +43,10 @@ class DetailConference extends StatelessWidget {
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Image.network(urlImage),
|
// Image.network(urlImage),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
conference.title,
|
widget.items.title,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|
@ -53,11 +58,11 @@ class DetailConference extends StatelessWidget {
|
||||||
style: const TextStyle(fontSize: 16, color: Colors.black),
|
style: const TextStyle(fontSize: 16, color: Colors.black),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'${conference.place}, ${conference.city}, ${conference.state}, ${conference.country}',
|
'${widget.items.place}, ${widget.items.city}, ${widget.items.state}, ${widget.items.country}',
|
||||||
style: const TextStyle(fontSize: 16, color: Colors.black),
|
style: const TextStyle(fontSize: 16, color: Colors.black),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Actividad: ${conference.activity}',
|
'Actividad: ${widget.items.activity}',
|
||||||
style: const TextStyle(fontSize: 16, color: Colors.black),
|
style: const TextStyle(fontSize: 16, color: Colors.black),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class HomePage extends StatefulWidget {
|
||||||
|
const HomePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HomePage> createState() => _HomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomePageState extends State<HomePage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_html/flutter_html.dart';
|
||||||
|
import 'package:lgcc/models/item_model.dart';
|
||||||
|
import 'package:lgcc/providers/wordpress_service.dart';
|
||||||
|
import 'package:lgcc/pages/detail_item.dart';
|
||||||
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
|
||||||
|
class ItemsList extends StatelessWidget {
|
||||||
|
final dynamic itemDetail;
|
||||||
|
final String type;
|
||||||
|
|
||||||
|
const ItemsList({Key? key, required this.type, this.itemDetail})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(type),
|
||||||
|
centerTitle: true,
|
||||||
|
backgroundColor: Color(0xFFE5EBFD),
|
||||||
|
),
|
||||||
|
body: _buildItemListView(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildItemListView(BuildContext context) {
|
||||||
|
final WordpressService wordpressService = WordpressService();
|
||||||
|
return FutureBuilder<List<dynamic>>(
|
||||||
|
future: wordpressService.fetchItems(type),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return Center(child: Text('Error: ${snapshot.error}'));
|
||||||
|
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
||||||
|
return const Center(child: Text('No hay items disponibles.'));
|
||||||
|
} else {
|
||||||
|
final List<ItemModel> items = snapshot.data!.cast<ItemModel>();
|
||||||
|
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: items.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final item = items[index];
|
||||||
|
return ListTile(
|
||||||
|
title: Text(item.title),
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => DetailItem(items: item),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:lgcc/models/conferences_model.dart';
|
import 'package:lgcc/models/item_model.dart';
|
||||||
|
|
||||||
class DirectusService {
|
class DirectusService {
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ Future<List<dynamic>> getConferences() async {
|
||||||
}());
|
}());
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final data = jsonDecode(response.body)['data'];
|
final data = jsonDecode(response.body)['data'];
|
||||||
return data.map((item) => ConferencesModel.fromJson(item)).toList();
|
return data.map((item) => ItemModel.fromJson(item)).toList();
|
||||||
} else {
|
} else {
|
||||||
throw Exception('Failed to load conferences');
|
throw Exception('Failed to load conferences');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:lgcc/models/item_model.dart';
|
||||||
|
|
||||||
|
class WordpressService {
|
||||||
|
|
||||||
|
String getBaseUrlType(String type) {
|
||||||
|
return 'https://${type}wp.carpa.com/v5/items/?cache=false';
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<ItemModel>> fetchItems(String type) async {
|
||||||
|
final baseUrl = getBaseUrlType(type);
|
||||||
|
final response = await http.get(Uri.parse('$baseUrl&f=list'));
|
||||||
|
print('Fetching items from: $response');
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final List<dynamic> jsonData = json.decode(response.body);
|
||||||
|
return jsonData.map((item) => ItemModel.fromJson(item)).toList();
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load items');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<ResultModel>> fetchYearsParam(String type ) async {
|
||||||
|
final baseUrl = getBaseUrlType(type);
|
||||||
|
final response = await http.get(Uri.parse(baseUrl + '&years'));
|
||||||
|
print('Fetching years from: $baseUrl');
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final List<dynamic> jsonData = json.decode(response.body);
|
||||||
|
return jsonData.map((item) => ResultModel.fromJson(item)).toList();
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load years');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -131,6 +131,14 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
google_nav_bar:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: google_nav_bar
|
||||||
|
sha256: bb12dd21514ee1b041ab3127673e2fd85e693337df308f7f2b75cd1e8e92eaf4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.7"
|
||||||
html:
|
html:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ dependencies:
|
||||||
flutter_dotenv: ^5.2.1
|
flutter_dotenv: ^5.2.1
|
||||||
flutter_html: ^3.0.0
|
flutter_html: ^3.0.0
|
||||||
flutter_markdown: ^0.7.7+1
|
flutter_markdown: ^0.7.7+1
|
||||||
|
google_nav_bar: ^5.0.7
|
||||||
http: ^1.4.0
|
http: ^1.4.0
|
||||||
intl: ^0.20.2
|
intl: ^0.20.2
|
||||||
path: ^1.9.1
|
path: ^1.9.1
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue