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
29 changes: 22 additions & 7 deletions .docs/DATA.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
# Data guide

## Data stored in SecureStore
Everything stays on the device: UniceNotes has no server of its own and never uploads personal data.
All keys are listed in `src/utils/storage.ts`.

## SecureStore

<p align="center">
<img src="https://docs.expo.dev/static/images/packages/expo-secure-store.png" alt="SecureStore" width="50"/>
</p>

This data is stored in the secure enclave (Keychain from Apple / Keystore from Android) of the device, which is a secure storage system that is used to store sensitive data. The data is encrypted and can only be accessed by the user with biometrical authentication or a password (phone PIN).
Encrypted storage backed by the iOS Keychain / Android Keystore.

- ```username```: Username of the user
- `adeid`: ADE timetable code, either a student number or a program id ending with `-VET`

## Data stored in AsyncStorage
## AsyncStorage

<p align="center">
<img src="https://docs.expo.dev/static/images/packages/expo-file-system.png" alt="AsyncStorage" width="50"/>
</p>

This data is stored in the AsyncStorage of the device, which is a storage system that is used to store data. The data is not encrypted and can be accessed by the user.
Unencrypted key-value storage for non-sensitive preferences.

- `theme`: selected color palette (`azur`, `menthe`, `lavande`, `ambre`)
- `haptics`: `"false"` when haptic feedback is disabled
- `liveActivities`: `"false"` when the iOS Live Activity is disabled
- `oobeCompleted`: `"true"` once the first-launch setup is done
- `releaseNotesVersion`: last app version whose release notes were shown
- `adeProjectOverride`: ADE project (school year) picked manually, absent in automatic mode
- `favoriteRooms`: ids of the pinned rooms (3 max)
- `pinnedApps`: ids of the ENT services pinned to the home screen's quick access (3 max)
- `androidWidgetTimeline`: upcoming classes read by the Android widget

## File system

- `calendar.json` (document directory): last downloaded timetable with its ADE code and download date, shown while offline

- ```haptics```: Boolean value to check if the user has chosen to enable haptics
- ```calendar```: Array of objects containing the calendar events
17 changes: 0 additions & 17 deletions .docs/ERRORS.md

This file was deleted.

48 changes: 12 additions & 36 deletions .docs/HAPTICS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,15 @@

<p align="center">
<img src="https://docs.expo.dev/static/images/packages/expo-haptics.png" alt="Haptics" width="50"/>

## New

### Inputs

Text Input -> ```haptics(selection)```

Refresh Input -> ```haptics(light)```

### Buttons

Normal Button -> ```haptics(medium)```

URL Buttons -> ```haptics(selection)```

Logout Button -> ```haptics(heavy)```

Delete Button -> ```haptics(warning)```

## Deprecated

### Inputs

Text Input -> ```Haptics.selectionAsync()```

Refresh Input -> ```Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)```

### Buttons

Normal Button -> ```Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium)```

URL Buttons -> ```Haptics.selectionAsync()```

Logout Button -> ```Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy)```

Delete Button -> ```Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning)```
</p>

Always go through `haptics()` from `src/utils/haptics.ts`: it does nothing when the user disabled haptic feedback in the settings.

| Interaction | Call |
| --- | --- |
| Navigation (open a screen, go back, open a menu) | `haptics('light')` |
| Main action (open the timetable, refresh, retry) | `haptics('medium')` |
| Choice (chip, switch, list item, theme, link) | `haptics('selection')` |
| Action completed (timetable saved, data deleted) | `haptics('success')` |
| Limit reached, destructive confirmation | `haptics('warning')` |
| Failure | `haptics('error')` |
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
EXPO_PUBLIC_ADE_TOKEN=

# clés Measure (suivi des erreurs), lues par app.config.js
MEASURE_ANDROID_API_KEY=
MEASURE_IOS_API_KEY=
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
check:
name: Lint & typecheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci --ignore-scripts
- run: npm run lint
- run: npm run typecheck
Comment on lines +10 to +20
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ yarn-error.*
*.pem

# local env files
.env/
.env
.env*.local

# typescript
Expand All @@ -44,3 +44,4 @@ app-example
# generated native folders
/ios
/android
/modules
5 changes: 5 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"singleQuote": true,
"printWidth": 120,
"trailingComma": "all"
}
48 changes: 38 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,34 @@
## ⚠️ Documentation

- Données : [Voir la documentation](https://github.com/UniceApps/UniceNotes/tree/main/.docs/DATA.md)
- Erreurs : [Voir la documentation](https://github.com/UniceApps/UniceNotes/tree/main/.docs/ERRORS.md)
- Haptics : [Voir la documentation](https://github.com/UniceApps/UniceNotes/tree/main/.docs/HAPTICS.md)
- API ADE : [Voir la documentation](https://github.com/UniceApps/UniceNotes/tree/main/.docs/ADE_API.md)
- Utilisation : [Voir la documentation](https://github.com/UniceApps/UniceNotes/tree/main/.docs/USAGE.md)
- API : [Voir la documentation](https://github.com/UniceApps/UniceAPI)

## 🗂️ Architecture

```
modules/
├── content-scroll/ module natif local (iOS) : la barre d'onglets se réduit au défilement
└── web-session/ module natif local : garde la connexion aux services de l'ENT (cookies de session)
src/
├── app/ écrans (expo-router : un fichier = une route, (tabs)/ = barre d'onglets)
├── components/
│ ├── ui/ briques communes : Screen, Card, ListItem, Tile, Sheet, Banner…
│ └── … composants propres à un écran (home, rooms, timetable, browser, ent, appearance)
├── context/ réglages et emploi du temps partagés par toute l'app
├── hooks/ logique réutilisable des écrans
├── services/ accès réseau : ADE, UniceAPI, cache, widgets
├── theme/ palettes Material 3 et thème choisi
├── utils/ fonctions pures : dates, couleurs, parseurs ADE…
└── widgets/ widgets iOS / Android et Live Activity
```

L'emploi du temps n'est téléchargé qu'à un seul endroit (`src/context/CalendarContext.tsx`) : l'accueil, l'écran emploi du temps, les widgets et la Live Activity partagent les mêmes données.

Les services de l'ENT (`src/constants/ent.ts`) s'ouvrent dans le navigateur de l'app (`src/app/browser.tsx`), qui n'accepte que les services de ce catalogue : un lien profond ne peut pas lui faire ouvrir une autre adresse.

## ⚙️ Contribution

Merci pour ton intérêt pour le projet ! Si tu souhaites contribuer, contacte-nous grâce à l'email suivant : [app at metrixmedia.fr](mailto://app@metrixmedia.fr) ou en créant une issue / pull request sur GitHub.
Expand All @@ -47,33 +70,38 @@ L'application UniceNotes utilise :

avec ton consentement (en te connectant sur l'application et en acceptant les conditions d'utilisation) afin de te fournir une expérience utilisateur optimale.
\
Les données critiques sont stockées dans un format **crypté** dans la Keychain d'Apple / Keystore d'Android et ne peuvent être déchiffrées que par l'utilisateur lorsqu'il s'identifie grâce à un code ou grâce à une option de connxion biométrique. [Voir l'API SecureStore](https://docs.expo.dev/versions/latest/sdk/securestore/)
Les données critiques sont stockées dans un format **chiffré** dans la Keychain d'Apple / Keystore d'Android et ne peuvent être déchiffrées que par l'utilisateur lorsqu'il s'identifie grâce à un code ou grâce à une option de connexion biométrique. [Voir l'API SecureStore](https://docs.expo.dev/versions/latest/sdk/securestore/)
\
Les données non-critiques sont stockées dans un stockage persistant nommé AsyncStorage de React Native. [Voir l'API AsyncStorage](https://react-native-async-storage.github.io/async-storage/docs/usage/)

## 🛠️ Build

Pour construire l'application, vous aurez besoin de Node.js, npm, Expo CLI, EAS CLI et un compte Expo.
Pour construire l'application, vous aurez besoin de Node.js, npm, EAS CLI et un compte Expo.

> [!IMPORTANT]
> Attention, vous devez posséder un compte payant Apple Developer ou Google Play Console pour pouvoir construire l'application pour iOS ou Android.

```bash
# Installer Expo CLI et EAS CLI
npm install -g expo-cli eas-cli
# Installer EAS CLI
npm install -g eas-cli

# Cloner le dépôt
git clone https://github.com/UniceApps/UniceNotes.git

# Aller dans le dossier
cd UniceNotes

# Installer les dépendances
npm install

# Renseigner le jeton ADE et les clés Measure
cp .env.example .env

# Vérifier le code
npm run lint
npm run typecheck

# Démarrer l'application en mode développement
# Vous devez posséder Expo Go sur votre appareil
npx expo
# L'app utilise des modules natifs (widgets, icônes…) : Expo Go ne suffit pas, il faut un build de développement
npx expo run:ios # ou npx expo run:android

# Construire l'application
eas login
Expand All @@ -93,7 +121,7 @@ Toute ressemblance avec le nom de l'application, le logo et l'interface ne saura

Toute utilisation de l'application UniceNotes est sous la seule responsabilité de l'utilisateur.

Cette application agit comme un client internet où l'utilisateur effectue des pseudos-requêtes (GET HTTPS) sur l'intranet de l'Université Côte d'Azur à travers des API exposées. Cette application ne contient aucun code malveillant et ne vise pas à nuire à l'Université Côte d'Azur ou à ses utilisateurs. Les éventuelles suspiscions de "fuites de données" sont infondées dûes à la nature de l'application (les données sont stockées sur l'appareil de l'utilisateur et non sur des serveurs tiers).
Cette application agit comme un client internet où l'utilisateur effectue des pseudos-requêtes (GET HTTPS) sur l'intranet de l'Université Côte d'Azur à travers des API exposées. Cette application ne contient aucun code malveillant et ne vise pas à nuire à l'Université Côte d'Azur ou à ses utilisateurs. Les éventuelles suspicions de "fuites de données" sont infondées du fait de la nature de l'application (les données sont stockées sur l'appareil de l'utilisateur et non sur des serveurs tiers).

## 🤝 Conditions d'utilisation :
[Consulter les conditions d'utilisation](https://notes.metrixmedia.fr/eula)
Expand Down
2 changes: 1 addition & 1 deletion app.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ module.exports = ({ config }) => {
github_hash: process.env.EAS_BUILD_GIT_COMMIT_HASH,
},
};
};
};
15 changes: 4 additions & 11 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"expo": {
"name": "UniceNotes",
"slug": "unicenotes",
"version": "3.3.0",
"version": "4.0.0",
"githubUrl": "https://github.com/UniceApps/UniceNotes",
"orientation": "portrait",
"icon": "./src/assets/icon.png",
Expand All @@ -22,11 +22,11 @@
"tinted": "./src/assets/ios/tinteddark.png"
},
"infoPlist": {
"NSFaceIDUsageDescription": "Connecte-toi sur l'application grâce à l'authentification biométrique.",
"NSNotificationsUsageDescription": "Reçois des notifications pour être informé de diverses choses.",
"CFBundleLocalizations": ["fr"],
"CFBundleDevelopmentRegion": "fr",
"CADisableMinimumFrameDurationOnPhone": true
"CADisableMinimumFrameDurationOnPhone": true,
"NSCameraUsageDescription": "Les services de l'ENT ouverts dans l'application peuvent utiliser l'appareil photo, par exemple pour scanner un QR code d'émargement.",
"NSMicrophoneUsageDescription": "Les services de l'ENT ouverts dans l'application peuvent utiliser le micro, par exemple pour une visioconférence."
},
"config": {
"usesNonExemptEncryption": false
Expand All @@ -40,17 +40,10 @@
"backgroundColor": "#FFFFFF"
}
},
"extra": {
"eas": {
"projectId": "ec0ebd57-7227-4cd2-a71e-344e0a5fffe5"
},
"github_hash": "$(EAS_BUILD_GIT_COMMIT_HASH)"
},
"owner": "hugofnm",
"plugins": [
"expo-router",
"expo-image",
"expo-sharing",
"expo-status-bar",
"expo-font",
"expo-secure-store",
Expand Down
4 changes: 3 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import 'expo-router/entry';
import './src/widgets/NextClassWidget';

// enregistre la tâche de fond du widget Android dès le démarrage
import './src/widgets/NextClassWidget';
6 changes: 6 additions & 0 deletions modules/content-scroll/expo-module.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"platforms": ["apple"],
"apple": {
"modules": ["ContentScrollModule"]
}
}
1 change: 1 addition & 0 deletions modules/content-scroll/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ContentScrollMarker } from './src/ContentScrollMarker';
23 changes: 23 additions & 0 deletions modules/content-scroll/ios/ContentScroll.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Pod::Spec.new do |s|
s.name = 'ContentScroll'
s.version = '1.0.0'
s.summary = 'Liste principale des onglets'
s.description = 'Declare la ScrollView d un onglet a UIKit pour que iOS 26 reduise la barre d onglets au defilement'
s.author = ''
s.homepage = 'https://docs.expo.dev/modules/'
s.platforms = {
:ios => '16.4'
}
s.source = { git: '' }
s.static_framework = true
s.swift_version = '5.9'

s.dependency 'ExpoModulesCore'

# Swift/Objective-C compatibility
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
}

s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
end
Loading
Loading