inshorts_flutter 0.0.4
inshorts_flutter: ^0.0.4 copied to clipboard
A Flutter package to fetch news from InShorts using its private API. Supports multiple categories and languages.
import 'package:flutter/material.dart';
import 'package:inshorts_flutter/inshorts_flutter.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'InShorts News',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.deepPurple,
),
home: const HomePage());
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
TabController? _controller;
List categories = [NewsType.allNews, NewsType.trending, NewsType.topStories, NewsType.business];
@override
void initState() {
super.initState();
_controller = TabController(length: categories.length, vsync: this);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('InShorts News'),
bottom: TabBar(
controller: _controller,
tabs: categories.map((e) => Tab(text: InShorts.getNewsTitle(e))).toList(),
),
),
body: TabBarView(
controller: _controller,
children: categories
.map((e) => FutureBuilder<Data>(
future: InShorts.getNews(newsType: e, language: Language.en),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data?.newsList?.length ?? 0,
itemBuilder: (context, index) {
News? news = snapshot.data?.newsList?[index];
if (news == null || news.newsObj == null) {
return const SizedBox.shrink();
}
final obj = news.newsObj!;
return Card(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (obj.imageUrl != null)
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(
obj.imageUrl!,
height: 80,
width: 80,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) =>
const SizedBox(height: 80, width: 80, child: Center(child: Icon(Icons.broken_image, size: 30))),
),
),
const SizedBox(width: 12),
Expanded(
child: Text(
obj.title ?? 'No Title',
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
),
],
),
const SizedBox(height: 8),
Text(
obj.content ?? '',
maxLines: 4,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 13, color: Colors.grey[800], height: 1.3),
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
obj.sourceName ?? 'Unknown',
style: const TextStyle(fontSize: 11, fontWeight: FontWeight.bold, color: Colors.deepPurple),
),
if (obj.authorName != null)
Text(
obj.authorName!,
style: const TextStyle(fontSize: 11, color: Colors.grey),
),
],
),
],
),
),
);
},
);
} else if (snapshot.hasError) {
return const Center(child: Text('Errr'));
}
return const Center(child: CircularProgressIndicator());
}))
.toList(),
),
);
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
}