Table of Contents
The AEGEE-Leiden App
Introduction
The AEGEE-Leiden App is a mobile application designed for members of AEGEE-Leiden, a European student organization. This app provides users with easy access to events, news, and other important information related to the organization. It is available on both Android and iOS platforms, as well as a web version for broader accessibility.
Features
- Members: Members can create an account and customize their profile with personal information.
- Events: View upcoming events in the calendar and get detailed information about each event. Admins can create and manage events.
- Posts: Stay up-to-date with the latest news and announcements from AEGEE-Leiden in the feed. All members can create posts, but only admins can publish them.
- Interactions: Members can comment on posts and events and let others know to which events they are going.
- Resources: Access important documents and resources related to the organization, such as photo albums, Eurokeys editions, booklets, and ALV documents.
- Notifications: Receive push notifications for new posts, comments, and events.
- Admin Panel: Admins have access to an admin panel where they can manage new users and posts, as well as send custom push notifications.
- External Links: Links and resources not integrated into the app can be accessed through the links section of the app's sidebar.
- Settings: Users can customize their app experience by changing the theme, language, and notification settings.
Documentation
Both the functional and technical documentation can be found on the automatically generated Docs page. To board members, the site may seem daunting at first, but most of the important information for board members can be found in the 'Topics' section of the side menu, which contains descriptions to all the different pages in the app as well as a topic called Services which contains information about the different (external) services the app uses. For one service, being the Cloud Functions, there is a dedicated topic page. This is because the service covers a lot of functionality that are not immediately clear to regular app users (such as how new activities in the app are automatically added to the AEGEE Google Calendar). with If any information is missing or unclear, please let us know so we can improve the documentation.
Development
This section is intended for developers who want to contribute to the app. If you are a board member or user of the app, you can ignore this section.
Ecosystem
Before starting out, it is important to understand all the different services, tools, and platforms that are relevant to the development process. The app is built using the following technologies:
- Development Platform: The app's code is hosted on our GitHub repository, where we manage issues, pull requests, and releases.
- Environments: The app has two environments:
devandprod. Thedevenvironment is used for development and testing, while theprodenvironment is used for the production version of the app. - Frontend: The app is built using the Flutter framework, which allows for cross-platform app development. The app is written in Dart.
- Backend: The app uses Firebase for most of its backend services. Developers can request access to the Production Firebase Project and Development Firebase Project. Aside from Firebase, some of the cloud computing aspects of the app are handled on the somewhat related Google Cloud Platform. Here, too, we have a Production GCP Project and a Development GCP Project. The features that we use are:
- Authentication: Firebase Authentication is used for user authentication.
- Firestore: Firestore is used as the database for storing posts, events, and other information.
- Storage: Firebase Storage is used for storing images such as event banners and user profile pictures.
- Cloud Messaging: Firebase Cloud Messaging is used to enable push notifications.
- Functions: Firebase Functions are used for server-side logic, such as sending push notifications on specific events and executing more sensitive operations such as deleting users and giving users admin rights. It is this aspect of the app that is most closely related to the Google Cloud Platform, as the functions are written in Node.js and run on Google's servers. Additionally, we have some service accounts set up for a variety of tasks, such as adding new events to the AEGEE-Leiden Google Calendar and fetching data from the AEGEE-Leiden Google Drive.
- Hosting: Firebase Hosting is used to host the web version of the app, which is accessible at app.aegee-leiden.nl.
- Extensions: We use the 'Resize Images' extension to resize images uploaded by users to allow for thumbnails and a consistent format.
- Remote Config: Remote Config is used to store configuration values that can be updated without updating the app. Currently, this is only used for providing the latest app version and the links to 'quick access' items on the ALV page.
- Content Management: Aside from data stored in Firestore and Firebase Storage, the app also uses Google Drive to store some resources. These are organised as follows:
- Intranet Drive: This drive contains everything that is displayed on the resources page of the app. This includes photo albums, Eurokeys editions, booklets, and ALV documents.
- AppTeam Drive: The cms folder in this drive contains the Terms and Conditions of the App as well as the 'Discounts' document that can be accessed from the 'Links' section of the app.
- App Stores: The app is available on both the Google Play Store and the Apple App Store. Publishing Android apps is done through the Google Play Console, while publishing iOS apps is done through App Store Connect.
- CI/CD: The app uses GitHub Actions for various CI/CD tasks, although this is still a work in progress. The workflows can be found in the workflows folder of the repository.
- Testing: While some tests have been written for the app, there is not yet a comprehensive testing strategy in place. The tests can be found in the test folder of the repository and are run using the
flutter testcommand. - Local Storage: The app uses the shared_preferences package to store user preferences locally on the device. While only a few preferences are currently stored, is is good to be aware of this functionality.
- Secrets: The app uses a variety of secrets, such as API keys and service account credentials. You can download these secrets from the keys folder in the AppTeam Drive. Which keys you need depends on the kind of tasks that you are working on, but having the
.envfile in the root folder is one of the most important things to get started.
Getting Started
To get started with the development of the app, you will need to set up your development environment. This includes installing Flutter, cloning the project, and configuring your IDE. For a more detailed guide on how to get started, please refer to the wiki.
Once you have set up your development environment, you can start working on the app. Here are some common commands that you will need to use:
- Install dependencies: Before you can run the app, you need to install the dependencies. You can do this by running
flutter pub getin the root folder of the project. - Generate code: The app uses code generation for various tasks, such as generating models and routes. You can run the code generators by running
dart run build_runner buildin the root folder of the project. You can also usedart run build_runner watchto rerun the generator on file changes, but if you are not actively working on the generators, it is better to run the build command only when needed. - Run the app: You can run the app on an emulator or a physical device. Ensure you have build flavors set up correctly. Then run the app using
flutter run --flavor dev --dart-define=IS_DEV=truefor the development version of the app.
Contributing
We use issues and branches for development. These are merged into the master branch with pull requests. Releases are preserved on the stable channel.
Commit messages
We follow the Angular Commit Message Guidelines. Commits should be in the format
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
Where type is any of the following:
- feat: A new feature
- fix: A bug fix
- docs: Documentation only changes
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- refactor: A code change that neither fixes a bug nor adds a feature
- perf: A code change that improves performance
- test: Adding missing or correcting existing tests
- chore: Changes to the build process or auxiliary tools and libraries such as documentation generation
Tools and tips
To make development easier, you can use the following tools and tips. Some assume you are using Visual Studio Code as your IDE, although other IDEs may have similar functionality.
- Flutter and Dart extensions: Install the Flutter and Dart extensions in Visual Studio Code for better support for Flutter development.
- GitHub Copilot: Install the GitHub Copilot extension in Visual Studio Code for AI-powered code suggestions.
- Flutter Riverpod Snippets: Install the Flutter Riverpod Snippets extension in Visual Studio Code for easy access to common Riverpod snippets.
- FVM: Use FVM to manage Flutter versions. This allows you to switch between Flutter versions easily and avoid conflicts between projects.
- File Nesting: In the VS Code settings, enable the Explorer>File Nesting setting to group related files together in the file explorer. You can add your own nesting rules in the settings. The following are recommended:
- Item:
*.dart, value:${capture}.g.dart,${capture}.freezed.dart, for generated files. - Item:
pubspec.yaml, value:pubspec.lock,.packages,.flutter-plugins,.flutter-plugins-dependencies,.metadata,*.yaml,*.yml,*.log,.fvmrc,upload_keystore.jks, for a cleaner project root.
- Item:
Testing
The app has a few tests that can be run using the flutter test --dart-define=IS_DEV=true command. Currently, not all tests are passing.
Libraries
- screens/settings/local_widgets/about
- screens/userProfile/local_widgets/actions
- screens/activity/local_widgets/actions
- screens/activity/activity
- widgets/activity/activityBuilder
- widgets/activity/activityCategory
- services/firebase/firestore/local/activityFunctions
- models/activityModel
- providers/activityProvider
- widgets/activity/activityTile
- screens/calendar/local_widgets/activityTileList
- screens/admin/admin
- services/firebase/functions/local/adminFunctions
- screens/resources/alv/alv
- screens/navigationShell/local_widgets/appBar
- screens/navigationShell/local_widgets/appBarActions
- services/firebase/authentication/authExceptionHandler
- services/firebase/authentication/authService
- services/firebase/authentication/authStatus
- services/firebase/authentication/local/authStream
- services/navigation/authStream
- utils/blurhashFunctions
- screens/createActivity/local_widgets/body
- screens/resources/booklets/booklets
- screens/calendar/calendar
- screens/calendar/calendarModel
- services/calendar/calendarService
- screens/calendar/local_widgets/calendarViewSelectionBar
- screens/createPost/local_widgets/callToActionButton
- screens/userProfile/local_widgets/chips
- services/firebase/cloudMessaging/cloudMessagingService
- screens/createActivity/local_widgets/color
- widgets/comment/commentForm
- widgets/comment/commentFormProvider
- services/firebase/firestore/local/commentFunctions
- models/commentModel
- widgets/comment/commentSection
- widgets/comment/commentSectionProvider
- widgets/comment/commentTile
- screens/confidentialBody/confidentialBody
- services/connectivity/connectivityService
- screens/createActivity/createActivity
- screens/createActivity/createActivityProvider
- widgets/activity/createActivityResult
- services/firebase/authentication/local/createDeleteFunctions
- screens/createPost/createPost
- screens/createPost/createPostProvider
- screens/createPost/local_widgets/createPostResult
- screens/navigationShell/local_widgets/currentRouteTitle
- providers/currentUserProvider
- utils/custom_icons
- models/customClaimsModel
- screens/admin/local_widgets/customNotificationPage
- utils/customQuillEditors
- screens/createActivity/local_widgets/dateTimePicker
- screens/sidebar/local_widgets/destinations
- utils/dialogs
- screens/admin/local_widgets/disabledUsersList
- services/drive/driveApiService
- screens/resources/driveFileModel
- screens/userProfile/local_widgets/editableBirthday
- screens/userProfile/local_widgets/editablePhoneNumber
- widgets/post/editDeleteMenu
- screens/settings/local_widgets/emailResetForm
- screens/settings/local_widgets/emailResetTile
- env/env
- screens/resources/eurokeys/euroKeys
- screens/activity/local_widgets/europeanEventDescription
- utils/extensions
- screens/feed/feed
- services/drive/local/fetchFunctions
- screens/resources/local_widgets/fileTile
- screens/resources/local_widgets/fileTree
- screens/calendar/filterModel
- utils/firestoreConverters
- services/firebase/firestore/firestoreService
- screens/home/local_widgets/floatingActionButton
- screens/resources/local_widgets/folderExpansionTile
- screens/landing/local_widgets/formSwitcher
- services/firebase/functions/functionService
- services/firebase/remoteConfig/local/getConfigFunctions
- screens/calendar/local_widgets/getOlderActivitiesButton
- screens/home/home
- screens/home/homeModel
- utils/imagePickerAndCropper
- screens/inbox/inbox
- screens/inbox/inboxData
- services/firebase/firestore/local/inboxFunctions
- screens/inbox/inboxModel
- services/localNotifications/local/initializationSettings
- providers/isInAsyncProvider
- screens/landing/landing
- screens/landing/local_widgets/landingButton
- screens/landing/local_widgets/landingFormField
- screens/landing/landingModel
- screens/sidebar/local_widgets/linkDestination
- screens/createPost/local_widgets/linkedActivityMenu
- screens/createActivity/local_widgets/linkedUrl
- screens/calendar/local_widgets/listCalendarView
- screens/settings/local_widgets/localePreferenceTile
- services/localNotifications/localNotification
- screens/activity/local_widgets/localParticipantsSection
- services/localStorage/localStorage
- screens/createActivity/local_widgets/location
- screens/landing/login/login
- services/firebase/authentication/local/logInOrOutFunctions
- main
- screens/confidentialBody/local_widgets/memberInfo
- screens/members/members
- widgets/user/nameTag
- screens/navigationShell/local_widgets/narrowViewAppBarLeading
- screens/feed/local_widgets/newEventTile
- widgets/user/noAvatarTile
- screens/resources/local_widgets/node
- screens/createActivity/local_widgets/notificationCheckbox
- services/firebase/cloudMessaging/local/notificationFunctions
- screens/navigationShell/local_widgets/notificationInboxIcon
- screens/settings/local_widgets/notificationOptions
- services/navigation/notificationRedirectStream
- screens/inbox/local_widgets/notificationTile
- screens/settings/local_widgets/notificationToggles
- widgets/user/offlineNameTag
- widgets/user/offlineProfilePicture
- services/firebase/firestore/local/participantFunctions
- screens/activity/local_widgets/participantsModel
- screens/activity/local_widgets/participantType
- screens/activity/local_widgets/participateSection
- screens/landing/passwordReset/passwordReset
- screens/settings/local_widgets/passwordResetTile
- services/localNotifications/local/permissionFunctions
- screens/navigationShell/local_widgets/photoAlbumButton
- screens/createActivity/local_widgets/photoAlbumCheckbox
- screens/resources/photos/photos
- screens/resources/local_widgets/photoUpload
- screens/createActivity/local_widgets/pickBannerButton
- utils/pluralResolver
- screens/post/post
- screens/createPost/local_widgets/postBody
- widgets/post/postCard
- screens/feed/postCreationDateModel
- services/firebase/firestore/local/postFunctions
- screens/post/postModel
- models/postModel
- screens/settings/local_widgets/privacyStatement
- services/firebase/functions/local/profileFunctions
- widgets/user/profilePicture
- utils/providerObserver
- screens/sidebar/local_widgets/quickLinksDialog
- services/localNotifications/local/receivedNotificationFunctions
- screens/activity/local_widgets/referencedPostPage
- screens/landing/register/register
- services/firebase/remoteConfig/remoteConfigService
- screens/userProfile/local_widgets/renameUserPage
- screens/resources/resources
- screens/resources/resourcesModel
- screens/resources/local_widgets/resourceType
- services/firebase/functions/local/retrieverFunctions
- services/navigation/router
- services/navigation/routerNotifier
- services/navigation/routes
- screens/createActivity/local_widgets/saveButton
- screens/createPost/local_widgets/savePostButton
- services/localNotifications/local/scheduleAndCancelFunctions
- screens/members/local_widgets/searchFormAndList
- screens/settings/settings
- screens/settings/local_widgets/signOutListTile
- screens/splash/splash
- services/firebase/storage/storageService
- l10n/strings.g
- services/firebase/cloudMessaging/local/subscriptionFunctions
- screens/calendar/local_widgets/tableCalendarView
- screens/calendar/local_widgets/tableCalendarwithBuilders
- screens/settings/local_widgets/termsOfService
- utils/themeData
- screens/settings/local_widgets/themeSwitcherTile
- utils/timeAgo
- screens/createActivity/local_widgets/title
- utils/typedefs
- screens/admin/unapprovedPostProvider
- screens/admin/local_widgets/unapprovedPostsList
- screens/admin/local_widgets/unapprovedPostWithButtons
- services/firebase/authentication/local/updateFunctions
- services/firebase/storage/local/uploadAndDeleteFunctions
- services/drive/local/uploadFunctions
- screens/userProfile/local_widgets/userInfoRow
- widgets/user/userListTile
- models/userModel
- screens/userProfile/userProfile
- screens/userProfile/local_widgets/userProfileName
- screens/userProfile/local_widgets/userProfilePicture
- providers/userProvider
- services/firebase/storage/utils
- utils/validators