Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
.vscode/
*.code-workspace

# Flutter/Dart/Pub related
**/doc/api/
Expand Down
15 changes: 15 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>

<!-- Deep linking -->
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:host="thalia.nu" />
<data android:path="/pizzas/" />
<data android:path="/events/" />
<data android:pathPattern="/events/.*/" />
<data android:pathPattern="/members/photos/.*/" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
Expand Down
2 changes: 1 addition & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/webview_flutter/ios"

SPEC CHECKSUMS:
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
flutter_web_auth: b7465086188ce4413d7e8b23622583784b9007a7
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
Expand Down
15 changes: 15 additions & 0 deletions ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,20 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>FlutterDeepLinkingEnabled</key>
<true/>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>thalia.nu</string>
<key>CFBundleURLSchemes</key>
<array>
<string>https</string>
</array>
</dict>
</array>
</dict>
</plist>
91 changes: 48 additions & 43 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:reaxit/navigation.dart';
import 'package:reaxit/providers/pizzas_provider.dart';
import 'package:reaxit/providers/notifications_provider.dart';
import 'package:reaxit/providers/theme_mode_provider.dart';
import 'package:reaxit/ui/screens/splash_screen.dart';
import 'package:reaxit/ui/styles/theme.dart';

import 'package:provider/provider.dart';
Expand All @@ -16,55 +16,60 @@ void main() {
}

class ThaliApp extends StatelessWidget {
final _routeInformationParser = ThaliaRouteInformationParser();
final _routerDelegate = ThaliaRouterDelegate();

@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<ThemeModeProvider>(
create: (_) => ThemeModeProvider(),
),
ChangeNotifierProvider<AuthProvider>(
create: (_) => AuthProvider(),
),
ChangeNotifierProxyProvider<AuthProvider, EventsProvider>(
create: (context) => EventsProvider(
Provider.of<AuthProvider>(context, listen: false),
),
update: (context, auth, events) => EventsProvider(auth),
),
ChangeNotifierProxyProvider<AuthProvider, MembersProvider>(
create: (context) => MembersProvider(
Provider.of<AuthProvider>(context, listen: false),
),
update: (context, auth, members) => MembersProvider(auth),
providers: [
ChangeNotifierProvider<ThemeModeProvider>(
create: (_) => ThemeModeProvider(),
),
ChangeNotifierProvider<AuthProvider>(
create: (_) => AuthProvider(),
),
ChangeNotifierProxyProvider<AuthProvider, EventsProvider>(
create: (context) => EventsProvider(
Provider.of<AuthProvider>(context, listen: false),
),
ChangeNotifierProxyProvider<AuthProvider, PhotosProvider>(
create: (context) => PhotosProvider(
Provider.of<AuthProvider>(context, listen: false),
),
update: (context, auth, photos) => PhotosProvider(auth),
update: (context, auth, events) => EventsProvider(auth),
),
ChangeNotifierProxyProvider<AuthProvider, MembersProvider>(
create: (context) => MembersProvider(
Provider.of<AuthProvider>(context, listen: false),
),
ChangeNotifierProxyProvider<AuthProvider, PizzasProvider>(
create: (context) => PizzasProvider(
Provider.of<AuthProvider>(context, listen: false),
),
update: (context, auth, pizzas) => PizzasProvider(auth),
update: (context, auth, members) => MembersProvider(auth),
),
ChangeNotifierProxyProvider<AuthProvider, PhotosProvider>(
create: (context) => PhotosProvider(
Provider.of<AuthProvider>(context, listen: false),
),
ChangeNotifierProxyProvider<AuthProvider, NotificationsProvider>(
create: (context) => NotificationsProvider(
Provider.of<AuthProvider>(context, listen: false),
),
update: (context, auth, pizzas) => NotificationsProvider(auth),
update: (context, auth, photos) => PhotosProvider(auth),
),
ChangeNotifierProxyProvider<AuthProvider, PizzasProvider>(
create: (context) => PizzasProvider(
Provider.of<AuthProvider>(context, listen: false),
),
],
child: Consumer<ThemeModeProvider>(
builder: (context, themeModeProvider, child) => MaterialApp(
title: 'ThaliApp',
theme: lightTheme,
darkTheme: darkTheme,
themeMode: themeModeProvider.themeMode,
home: SplashScreen(),
update: (context, auth, pizzas) => PizzasProvider(auth),
),
ChangeNotifierProxyProvider<AuthProvider, NotificationsProvider>(
create: (context) => NotificationsProvider(
Provider.of<AuthProvider>(context, listen: false),
),
));
update: (context, auth, pizzas) => NotificationsProvider(auth),
),
],
child: Consumer<ThemeModeProvider>(
builder: (context, themeModeProvider, child) => MaterialApp.router(
title: 'ThaliApp',
theme: lightTheme,
darkTheme: darkTheme,
themeMode: themeModeProvider.themeMode,
routeInformationParser: _routeInformationParser,
routerDelegate: _routerDelegate,
),
),
);
}
}
149 changes: 149 additions & 0 deletions lib/navigation.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:reaxit/providers/auth_provider.dart';
import 'package:reaxit/ui/screens/album_detail.dart';
import 'package:reaxit/ui/screens/album_list.dart';
import 'package:reaxit/ui/screens/calendar_screen.dart';
import 'package:reaxit/ui/screens/event_screen.dart';
import 'package:reaxit/ui/screens/login_screen.dart';
import 'package:reaxit/ui/screens/pizza_screen.dart';
import 'package:reaxit/ui/screens/welcome_screen.dart';

class ThaliaRouterDelegate extends RouterDelegate<List<Page>>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<List<Page>> {
final GlobalKey<NavigatorState> navigatorKey;

static ThaliaRouterDelegate of(BuildContext context) {
RouterDelegate delegate = Router.of(context).routerDelegate;
assert(delegate is ThaliaRouterDelegate, 'Delegate type must match.');
return delegate as ThaliaRouterDelegate;
}

ThaliaRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>();

List<Page> _stack = [MaterialPage(child: WelcomeScreen())];

@override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(
builder: (context, auth, child) {
if (auth.status == AuthStatus.SIGNED_OUT) {
_stack
..clear()
..add(MaterialPage(child: LoginScreen()));
}

return Navigator(
key: navigatorKey,
onPopPage: _onPopPage,
pages: auth.status == AuthStatus.INIT
? [MaterialPage(child: _SplashScreen())]
: _stack.toList(),
);
},
);
}

bool _onPopPage(route, result) {
if (!route.didPop(result)) return false;
if (_stack.length > 1) _stack.removeLast();
notifyListeners();
return true;
}

@override
Future<void> setNewRoutePath(List<Page> stack) async {
_stack
..clear()
..addAll(stack);
return SynchronousFuture(null);
}

/// Adds a page to the top of the stack.
void push(Page page) {
_stack.add(page);
notifyListeners();
}

/// Removes the top of the stack.
void pop() {
if (_stack.length > 1) _stack.removeLast();
notifyListeners();
}

/// Replaces the top of the stack.
void replace(Page page) {
_stack
..removeLast()
..add(page);
notifyListeners();
}

/// Replaces the current stack.
void replaceStack(List<Page> stack) {
_stack
..clear()
..addAll(stack);
notifyListeners();
}
}

class _SplashScreen extends StatelessWidget {
const _SplashScreen({
Key key,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return Container(
color: Color(0xFFE62272),
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
);
}
}

class ThaliaRouteInformationParser
implements RouteInformationParser<List<Page>> {
@override
Future<List<Page>> parseRouteInformation(routeInformation) async {
Uri uri = Uri.parse(routeInformation.location);
String path = uri.path;
List<String> segments = uri.pathSegments;

// Handle "/".
if (uri.pathSegments.length == 0)
return [MaterialPage(child: WelcomeScreen())];

if (RegExp('^/pizzas/\$').hasMatch(path)) {
return [
MaterialPage(child: WelcomeScreen()),
MaterialPage(child: PizzaScreen()),
];
} else if (RegExp('^/events/\$').hasMatch(path)) {
return [MaterialPage(child: CalendarScreen())];
} else if (RegExp('^/events/([0-9]+)/\$').hasMatch(path)) {
return [
MaterialPage(child: CalendarScreen()),
MaterialPage(child: EventScreen(int.parse(segments[1])))
];
} else if (RegExp('^/members/photos/([0-9]+)/\$').hasMatch(path)) {
return [
MaterialPage(child: AlbumList()),
MaterialPage(child: AlbumDetail(int.parse(segments[1])))
];
}

// Handle unknown path.
return [MaterialPage(child: WelcomeScreen())];
}

@override
RouteInformation restoreRouteInformation(configuration) {
return RouteInformation(location: "/");
}
}
4 changes: 3 additions & 1 deletion lib/providers/auth_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ class AuthProvider extends ChangeNotifier {
logOut() {
_helper.disconnect();
_status = AuthStatus.SIGNED_OUT;
notifyListeners();
}

Future<String> logIn() async {
// TODO: handle unexpected behaviour (e.g. clicking cancel)
try {
Comment thread
DeD1rk marked this conversation as resolved.
await _helper.getToken();
} on PlatformException catch (e) {
Expand All @@ -77,7 +79,7 @@ class AuthProvider extends ChangeNotifier {
return 'Unknown error';
}

_loadUserData();
await _loadUserData();
_status = AuthStatus.SIGNED_IN;
notifyListeners();
return 'success';
Expand Down
8 changes: 3 additions & 5 deletions lib/ui/components/album_card.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:reaxit/navigation.dart';
import 'package:reaxit/ui/screens/album_detail.dart';
import 'package:reaxit/models/album.dart';

Expand All @@ -11,11 +12,8 @@ class AlbumCard extends StatelessWidget {
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AlbumDetail(this._album.pk, this._album),
),
ThaliaRouterDelegate.of(context).push(
MaterialPage(child: AlbumDetail(this._album.pk, this._album)),
);
},
child: Stack(
Expand Down
Loading