mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-08-01 05:10:15 +02:00
Migrated to Material You
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:obtainium/pages/apps.dart';
|
||||
import 'package:obtainium/pages/home.dart';
|
||||
import 'package:obtainium/services/apps_provider.dart';
|
||||
import 'package:obtainium/services/source_service.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:workmanager/workmanager.dart';
|
||||
import 'package:dynamic_color/dynamic_color.dart';
|
||||
|
||||
void backgroundUpdateCheck() {
|
||||
Workmanager().executeTask((task, inputData) async {
|
||||
@@ -36,6 +37,7 @@ void main() async {
|
||||
await Workmanager().registerPeriodicTask(
|
||||
'update-apps-task', 'backgroundUpdateCheck',
|
||||
frequency: const Duration(minutes: 15),
|
||||
initialDelay: const Duration(minutes: 15),
|
||||
constraints: Constraints(networkType: NetworkType.connected));
|
||||
runApp(MultiProvider(
|
||||
providers: [ChangeNotifierProvider(create: (context) => AppsProvider())],
|
||||
@@ -43,16 +45,35 @@ void main() async {
|
||||
));
|
||||
}
|
||||
|
||||
var defaultThemeColour = const Color(0xFF69F0AE);
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Obtainium',
|
||||
theme: ThemeData(
|
||||
primarySwatch: Colors.blue,
|
||||
),
|
||||
home: const AppsPage());
|
||||
return DynamicColorBuilder(
|
||||
builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
|
||||
ColorScheme lightColorScheme;
|
||||
ColorScheme darkColorScheme;
|
||||
if (lightDynamic != null && darkDynamic != null) {
|
||||
lightColorScheme = lightDynamic.harmonized();
|
||||
darkColorScheme = darkDynamic.harmonized();
|
||||
} else {
|
||||
lightColorScheme = ColorScheme.fromSeed(seedColor: defaultThemeColour);
|
||||
darkColorScheme = ColorScheme.fromSeed(
|
||||
seedColor: defaultThemeColour, brightness: Brightness.dark);
|
||||
}
|
||||
|
||||
return MaterialApp(
|
||||
title: 'Obtainium',
|
||||
theme: ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: lightColorScheme,
|
||||
fontFamily: 'Metropolis'),
|
||||
darkTheme:
|
||||
ThemeData(useMaterial3: true, colorScheme: darkColorScheme),
|
||||
home: const HomePage());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -18,78 +18,72 @@ class _AddAppPageState extends State<AddAppPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Obtainium - Add App'),
|
||||
),
|
||||
body: Center(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const Spacer(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
hintText: 'https://github.com/Author/Project',
|
||||
helperText: 'Enter the App source URL'),
|
||||
controller: urlInputController,
|
||||
validator: (value) {
|
||||
if (value == null ||
|
||||
value.isEmpty ||
|
||||
Uri.tryParse(value) == null) {
|
||||
return 'Please enter a supported source URL';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
)),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: gettingAppInfo
|
||||
? null
|
||||
: () {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
return Center(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const Spacer(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'https://github.com/Author/Project',
|
||||
helperText: 'Enter the App source URL'),
|
||||
controller: urlInputController,
|
||||
validator: (value) {
|
||||
if (value == null ||
|
||||
value.isEmpty ||
|
||||
Uri.tryParse(value) == null) {
|
||||
return 'Please enter a supported source URL';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
)),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
|
||||
child: ElevatedButton(
|
||||
onPressed: gettingAppInfo
|
||||
? null
|
||||
: () {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
setState(() {
|
||||
gettingAppInfo = true;
|
||||
});
|
||||
SourceService()
|
||||
.getApp(urlInputController.value.text)
|
||||
.then((app) {
|
||||
var appsProvider = context.read<AppsProvider>();
|
||||
if (appsProvider.apps.containsKey(app.id)) {
|
||||
throw 'App already added';
|
||||
}
|
||||
appsProvider.saveApp(app).then((_) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
AppPage(appId: app.id)));
|
||||
});
|
||||
}).catchError((e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(e.toString())),
|
||||
);
|
||||
}).whenComplete(() {
|
||||
setState(() {
|
||||
gettingAppInfo = true;
|
||||
gettingAppInfo = false;
|
||||
});
|
||||
SourceService()
|
||||
.getApp(urlInputController.value.text)
|
||||
.then((app) {
|
||||
var appsProvider = context.read<AppsProvider>();
|
||||
if (appsProvider.apps.containsKey(app.id)) {
|
||||
throw 'App already added';
|
||||
}
|
||||
appsProvider.saveApp(app).then((_) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
AppPage(appId: app.id)));
|
||||
});
|
||||
}).catchError((e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(e.toString())),
|
||||
);
|
||||
}).whenComplete(() {
|
||||
setState(() {
|
||||
gettingAppInfo = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
child: const Text('Add'),
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
child: const Text('Add'),
|
||||
),
|
||||
const Spacer(),
|
||||
if (gettingAppInfo) const LinearProgressIndicator(),
|
||||
],
|
||||
),
|
||||
)),
|
||||
);
|
||||
),
|
||||
const Spacer(),
|
||||
if (gettingAppInfo) const LinearProgressIndicator(),
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@ class _AppPageState extends State<AppPage> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
child: ElevatedButton(
|
||||
onPressed: (app?.installedVersion == null ||
|
||||
appsProvider
|
||||
.checkAppObjectForUpdate(app!)) &&
|
||||
@@ -52,7 +52,7 @@ class _AppPageState extends State<AppPage> {
|
||||
? 'Install'
|
||||
: 'Update'))),
|
||||
const SizedBox(width: 16.0),
|
||||
OutlinedButton(
|
||||
ElevatedButton(
|
||||
onPressed: app?.currentDownloadId != null
|
||||
? null
|
||||
: () {
|
||||
@@ -85,7 +85,8 @@ class _AppPageState extends State<AppPage> {
|
||||
});
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Theme.of(context).errorColor),
|
||||
foregroundColor: Theme.of(context).errorColor,
|
||||
surfaceTintColor: Theme.of(context).errorColor),
|
||||
child: const Text('Remove'),
|
||||
),
|
||||
])),
|
||||
|
@@ -17,83 +17,39 @@ class _AppsPageState extends State<AppsPage> {
|
||||
var appsProvider = context.watch<AppsProvider>();
|
||||
appsProvider.getUpdates();
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Obtainium'),
|
||||
),
|
||||
body: Center(
|
||||
child: appsProvider.loadingApps
|
||||
? const CircularProgressIndicator()
|
||||
: appsProvider.apps.isEmpty
|
||||
? Text(
|
||||
'No Apps',
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: appsProvider.getUpdates,
|
||||
child: ListView(
|
||||
children: appsProvider.apps.values
|
||||
.map(
|
||||
(e) => ListTile(
|
||||
title: Text('${e.author}/${e.name}'),
|
||||
subtitle:
|
||||
Text(e.installedVersion ?? 'Not Installed'),
|
||||
trailing: e.installedVersion != null &&
|
||||
e.installedVersion != e.latestVersion
|
||||
? const Text('Update Available')
|
||||
: null,
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
AppPage(appId: e.id)),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
return Center(
|
||||
child: appsProvider.loadingApps
|
||||
? const CircularProgressIndicator()
|
||||
: appsProvider.apps.isEmpty
|
||||
? Text(
|
||||
'No Apps',
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
)
|
||||
: RefreshIndicator(
|
||||
onRefresh: appsProvider.getUpdates,
|
||||
child: ListView(
|
||||
children: appsProvider.apps.values
|
||||
.map(
|
||||
(e) => ListTile(
|
||||
title: Text('${e.author}/${e.name}'),
|
||||
subtitle:
|
||||
Text(e.installedVersion ?? 'Not Installed'),
|
||||
trailing: e.installedVersion != null &&
|
||||
e.installedVersion != e.latestVersion
|
||||
? const Text('Update Available')
|
||||
: null,
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => AppPage(appId: e.id)),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
bottomSheet: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Expanded(
|
||||
child: appsProvider.apps.values.toList().where((e) {
|
||||
return (e.installedVersion != null &&
|
||||
e.installedVersion != e.latestVersion);
|
||||
}).isNotEmpty
|
||||
? OutlinedButton(
|
||||
onPressed: () {
|
||||
appsProvider.installUpdates().catchError((e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(e.toString())),
|
||||
);
|
||||
});
|
||||
},
|
||||
child: const Text('Update All'))
|
||||
: Container()),
|
||||
const SizedBox(width: 16.0),
|
||||
OutlinedButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const AddAppPage()),
|
||||
);
|
||||
},
|
||||
child: const Text('Add App'),
|
||||
),
|
||||
])),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
41
lib/pages/home.dart
Normal file
41
lib/pages/home.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:obtainium/pages/add_app.dart';
|
||||
import 'package:obtainium/pages/apps.dart';
|
||||
import 'package:obtainium/pages/settings.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
State<HomePage> createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends State<HomePage> {
|
||||
int selectedIndex = 1;
|
||||
List<Widget> pages = [
|
||||
const SettingsPage(),
|
||||
const AppsPage(),
|
||||
const AddAppPage()
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Obtainium')),
|
||||
body: pages.elementAt(selectedIndex),
|
||||
bottomNavigationBar: NavigationBar(
|
||||
destinations: const [
|
||||
NavigationDestination(
|
||||
icon: Icon(Icons.settings), label: 'Settings'),
|
||||
NavigationDestination(icon: Icon(Icons.apps), label: 'Apps'),
|
||||
NavigationDestination(icon: Icon(Icons.add), label: 'Add App'),
|
||||
],
|
||||
onDestinationSelected: (int index) {
|
||||
setState(() {
|
||||
selectedIndex = index;
|
||||
});
|
||||
},
|
||||
selectedIndex: selectedIndex,
|
||||
));
|
||||
}
|
||||
}
|
20
lib/pages/settings.dart
Normal file
20
lib/pages/settings.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SettingsPage extends StatefulWidget {
|
||||
const SettingsPage({super.key});
|
||||
|
||||
@override
|
||||
State<SettingsPage> createState() => _SettingsPageState();
|
||||
}
|
||||
|
||||
class _SettingsPageState extends State<SettingsPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Text(
|
||||
'No Configurable Settings Yet.',
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
textAlign: TextAlign.center,
|
||||
));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user