fluffychat merge

This commit is contained in:
ggurdin 2026-02-04 14:42:00 -05:00
commit f5d01b17dc
No known key found for this signature in database
GPG key ID: A01CB41737CBB478
9 changed files with 874 additions and 974 deletions

View file

@ -13,4 +13,160 @@ To improve the process please make sure that you read the following guidelines c
6. Format the commit message as [Conventional Commits](https://www.conventionalcommits.org).
7. Format (`flutter format lib`) and sort impots (`dart run import_sorter:main --no-comments`) in all code files.
8. For bigger or complex changes (more than a couple of code lines) write an issue or refer to an existing issue and ask for approval from the maintainers (@krille-chan) **before** starting to implement it. This way you reduce the risk that your Pull Request get's declined.
9. Prefer simple and easy to maintain solutions over complexity and fancy ones.
9. Prefer simple and easy to maintain solutions over complexity and fancy ones.
# Code Style
FluffyChat tries to be as minimal as possible even in the code style. We try to keep the code clean, simple and easy to read. The source code of the app is under `/lib` with the main entry point `/lib/main.dart`.
<!-- editorconfig-checker-disable -->
<!-- prettier-ignore-start -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**
- [Directory Structure:](#directory-structure)
- [Separation of Controllers and Views](#separation-of-controllers-and-views)
- [Formatting](#formatting)
- [Code Analyzis](#code-analyzis)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- prettier-ignore-end -->
<!-- editorconfig-checker-enable -->
### Directory Structure:
- /lib
- /config
- app_config.dart
- ...Constants, styles and other configurations
- /utils
- handy_function.dart
- ...Helper functions and extensions
- /pages
- /chat
- chat.dart
- chat_view.dart
- /chat_list
- chat_list.dart
- chat_list_view.dart
- ...The pages of the app separated in Controllers and Views
- /widgets
- /layouts
- ...Custom widgets created for this project
- main.dart
Most of the business model is in the Famedly Matrix Dart SDK. We try to not keep a model inside of the source code but extend it under `/utils`.
### Separation of Controllers and Views
We split views and controller logic with stateful widgets as controller where the build method just builds a stateless widget which receives the state as the only parameter. A common controller would look like this:
```dart
// /lib/controller/enter_name_controller.dart
import 'package:flutter/material.dart';
class EnterName extends StatefulWidget {
@override
EnterNameController createState() => EnterNameController();
}
class EnterNameController extends State<EnterName> {
final TextEditingController textEditingController = TextEditingController();
String name = 'Unknown';
/// Changes the name with the content in the textfield. If the textfield is
/// empty, this breaks up and displays a SnackBar.
void setNameAction() {
if (textEditingController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('You have not entered your name'),
),
);
return;
}
setState(() => name = textEditingController.text);
}
@override
Widget build(BuildContext context) => EnterNameView(this);
}
```
So we have a controller for a `EnterName` view which as a `TextEditingController`, a state `name` and an action `void setNameAction()`. Actions must always be methods of a type, that we dont need to pass parameters in the corresponding view class and must have dartdoc comments.
The view class could look like this:
```dart
// /lib/views/enter_name_view.dart
import 'package:flutter/material.dart';
class EnterNameView extends StatelessWidget {
final EnterNameController controller;
const EnterNameView(this.controller, {Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Your name: ${controller.name}'),
),
body: Center(
child: TextField(
controller: controller.textEditingController,
),
),
floatingActionButton: FloatingActionButton(
onPressed: controller.setNameAction,
child: Icon(Icons.save),
),
);
}
}
```
Views should just contain code which describes the view. All other parameters or logic should be in the controller. The job of the view class is just to take the current state and build the widget tree and pipe the callbacks back. If there is any calulation necessary which is not solveable as a simple if-else or switch statement, it should be done in an external helper function unter `/lib/utils/`.
All file names must be lower_snake_case. All views must have a `View` suffix and all controller must have a `Controller` suffix. Widgets may have a controller too but they should pass the callbacks back to the view where possible. Calling one line methods directly in the view is only recommended if there is no need to pass a parameter.
To perform an action on state initialization we use the initState method:
```dart
@override
void initState() {
// TODO: implement initState
super.initState();
}
```
And the dispose method to perform an action on disposing:
```dart
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
```
To run code after the widget was created first we use the WidgetBindings in the initState:
```dart
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
// Do something when build is finished
});
super.initState();
}
```
### Formatting
We do not allow code with wrong formatting. Please run `flutter format lib` if your IDE doesn't do this automatically.
### Code Analyzis
We do not allow codes with dart errors or warnings. We use the [flutter_lints](https://pub.dev/packages/flutter_lints) package for static code analysis with additional rules under `analysis_options.yaml`.

View file

@ -7,8 +7,9 @@ FluffyChat is available on Android, iOS, Linux and as a web version. Desktop ver
* [Encryption](#encryption)
* [App Permissions](#app-permissions)
* [Push Notifications](#push-notifications)
* [PlayStore Safety Standards](#playstore-safety)
## Matrix<a id="matrix"/>
## <a id="matrix" href="#matrix">#</a> Matrix
FluffyChat uses the Matrix protocol. This means that FluffyChat is just a client that can be connected to any compatible matrix server. The respective data protection agreement of the server selected by the user then applies.
For convenience, one or more servers are set as default that the FluffyChat developers consider trustworthy. The developers of FluffyChat do not guarantee their trustworthiness. Before the first communication, users are informed which server they are connecting to.
@ -17,17 +18,17 @@ FluffyChat only communicates with the selected server and with [OpenStreetMap](h
More information is available at: [https://matrix.org](https://matrix.org)
## Database<a id="database"/>
## <a id="database" href="#database">#</a> Database
FluffyChat caches some data received from the server in a local sqflite database on the device of the user. On web indexedDB is used. FluffyChat always tries to encrypt the database by using SQLCipher and stores the encryption key in the [Secure Storage](https://pub.dev/packages/flutter_secure_storage) of the device.
More information is available at: [https://pub.dev/packages/sqflite](https://pub.dev/packages/sqflite) and [https://pub.dev/packages/sqlcipher_flutter_libs](https://pub.dev/packages/sqlcipher_flutter_libs)
## Encryption<a id="encryption"/>
## <a id="encryption" href="#encryption">#</a> Encryption
All communication of substantive content between Fluffychat and any server is done in secure way, using transport encryption to protect it.
FluffyChat also uses End-To-End-Encryption by using [libolm](https://gitlab.matrix.org/matrix-org/olm) and enables it by default for private chats.
## App Permissions<a id="app-permissions"/>
## <a id="app-permissions" href="#app-permissions">#</a> App Permissions
The permissions are the same on Android and iOS but may differ in the name. This are the Android Permissions:
@ -50,7 +51,7 @@ The user is able to send files from the device's file system.
#### Location
FluffyChat makes it possible to share the current location via the chat. When the user shares their location, FluffyChat uses the device location service and sends the geo-data via Matrix.
## Push Notifications<a id="push-notifications"/>
## <a id="push-notifications" href="#push-notifications">#</a> Push Notifications
FluffyChat uses the Firebase Cloud Messaging service for push notifications on Android and iOS. This takes place in the following steps:
1. The matrix server sends the push notification to the FluffyChat Push Gateway
2. The FluffyChat Push Gateway forwards the message in a different format to Firebase Cloud Messaging
@ -94,7 +95,7 @@ A typical push notification could look like this:
FluffyChat sets the `event_id_only` flag at the Matrix Server. This server is then responsible to send the correct data.
# Explanation of FluffyChat's Compliance with Google Play Store's Safety Standards
# <a id="playstore-safety" href="#playstore-safety">#</a> Explanation of FluffyChat's Compliance with Google Play Store's Safety Standards
FluffyChat is committed to promoting a safe and respectful environment for all users. As a Matrix client, FluffyChat connects users to various Matrix servers. Please note that FluffyChat does not host or manage any servers directly, and as such, we do not have the capability to enforce content moderation or deletion within the app itself.

File diff suppressed because it is too large Load diff

View file

@ -3438,6 +3438,8 @@
},
"donate": "Spenden",
"@donate": {},
"resume": "Fortsetzen",
"@resume": {},
"writeAMessageLangCodes": "Geben Sie in {l1} oder {l2} ein...",
"requests": "Anfragen",
"holdForInfo": "Klicken und halten für Wortinformationen.",

View file

@ -3399,6 +3399,45 @@
"@pause": {},
"resume": "Atosú",
"@resume": {},
"newSubSpace": "Fo-spás nua",
"@newSubSpace": {},
"moveToDifferentSpace": "Bog go spás difriúil",
"@moveToDifferentSpace": {},
"moveUp": "Bog suas",
"@moveUp": {},
"moveDown": "Bog síos",
"@moveDown": {},
"removeFromSpaceDescription": "Bainfear an comhrá as an spás ach beidh sé fós le feiceáil i do liosta comhrá.",
"@removeFromSpaceDescription": {},
"countChats": "comhráite {chats}",
"@countChats": {
"type": "String",
"placeholders": {
"chats": {
"type": "int"
}
}
},
"spaceMemberOf": "Ball spáis de {spaces}",
"@spaceMemberOf": {
"type": "String",
"placeholders": {
"spaces": {
"type": "String"
}
}
},
"spaceMemberOfCanKnock": "Is féidir le ball spáis de {spaces} cnagadh",
"@spaceMemberOfCanKnock": {
"type": "String",
"placeholders": {
"spaces": {
"type": "String"
}
}
},
"donate": "Tabhair Síntiús",
"@donate": {},
"writeAMessageLangCodes": "Clóscríobh i {l1} nó {l2}...",
"requests": "Iarratais",
"holdForInfo": "Bain triail as agus coinnigh síos le haghaidh eolas faoin bhfocal.",

View file

@ -3394,6 +3394,27 @@
"@pause": {},
"resume": "Continuar",
"@resume": {},
"newSubSpace": "Novo sub espazo",
"@newSubSpace": {},
"moveToDifferentSpace": "Mover a outro espazo",
"@moveToDifferentSpace": {},
"moveUp": "Mover arriba",
"@moveUp": {},
"moveDown": "Mover abaixo",
"@moveDown": {},
"removeFromSpaceDescription": "Vaise quitar a conversa do espazo pero seguirá aparecendo na túa lista de conversas.",
"@removeFromSpaceDescription": {},
"countChats": "{chats} conversas",
"@countChats": {
"type": "String",
"placeholders": {
"chats": {
"type": "int"
}
}
},
"donate": "Doar",
"@donate": {},
"writeAMessageLangCodes": "Escribe en {l1} ou {l2}...",
"requests": "Solicitudes",
"holdForInfo": "Fai clic e mantén para obter información sobre a palabra.",

View file

@ -3371,6 +3371,51 @@
"@declineInvitation": {},
"noMessagesYet": "Vēl nav ziņu",
"@noMessagesYet": {},
"longPressToRecordVoiceMessage": "Ilga piespiešana, lai ierakstītu balss ziņu.",
"@longPressToRecordVoiceMessage": {},
"pause": "Apturēt",
"@pause": {},
"resume": "Atsākt",
"@resume": {},
"newSubSpace": "Jauna apakšvieta",
"@newSubSpace": {},
"moveToDifferentSpace": "Pārvietot uz citu vietu",
"@moveToDifferentSpace": {},
"moveUp": "Pārvietot augšup",
"@moveUp": {},
"moveDown": "Pārvietot lejup",
"@moveDown": {},
"removeFromSpaceDescription": "Tērzēšana tiks noņemta no vietas, bet tā joprojām būs redzama tērzēšanu sarakstā.",
"@removeFromSpaceDescription": {},
"countChats": "{chats} tērzēšanas",
"@countChats": {
"type": "String",
"placeholders": {
"chats": {
"type": "int"
}
}
},
"spaceMemberOf": "{spaces} dalībnieks",
"@spaceMemberOf": {
"type": "String",
"placeholders": {
"spaces": {
"type": "String"
}
}
},
"spaceMemberOfCanKnock": "{spaces} dalībnieks var pieklauvēt",
"@spaceMemberOfCanKnock": {
"type": "String",
"placeholders": {
"spaces": {
"type": "String"
}
}
},
"donate": "Ziedot",
"@donate": {},
"ignore": "Bloķēt",
"ignoredUsers": "Bloķētie lietotāji",
"writeAMessageLangCodes": "Rakstiet {l1} vai {l2}...",

View file

@ -1921,10 +1921,10 @@ packages:
dependency: "direct main"
description:
name: qr_code_scanner_plus
sha256: a0f1ac8e13299b3db2646635f252fe2ec67222b848b24ed34d11052faf080bfa
sha256: "41f4a834a48d670d25e3917cb9f1dbb4742298a0b4ab60d82416b295b73931e1"
url: "https://pub.dev"
source: hosted
version: "2.0.12"
version: "2.0.13"
qr_image:
dependency: "direct main"
description:
@ -2137,10 +2137,10 @@ packages:
dependency: "direct main"
description:
name: share_plus
sha256: "3424e9d5c22fd7f7590254ba09465febd6f8827c8b19a44350de4ac31d92d3a6"
sha256: "14c8860d4de93d3a7e53af51bff479598c4e999605290756bbbe45cf65b37840"
url: "https://pub.dev"
source: hosted
version: "12.0.0"
version: "12.0.1"
share_plus_platform_interface:
dependency: transitive
description:

View file

@ -50,7 +50,7 @@ dependencies:
flutter_web_auth_2: ^3.1.1 # Version 4 blocked by https://github.com/MixinNetwork/flutter-plugins/issues/379
flutter_webrtc: ^1.2.0
geolocator: ^14.0.2
go_router: ^16.2.5
go_router: ^16.3.0
handy_window: ^0.4.0
html: ^0.15.4
http: ^1.5.0
@ -75,12 +75,12 @@ dependencies:
pretty_qr_code: ^3.5.0
provider: ^6.0.2
punycode: ^1.0.0
qr_code_scanner_plus: ^2.0.12
qr_code_scanner_plus: ^2.0.13
qr_image: ^1.0.0
receive_sharing_intent: ^1.8.1
record: ^6.1.1
scroll_to_index: ^3.0.1
share_plus: ^12.0.0
share_plus: ^12.0.1
shared_preferences: ^2.2.0 # Pinned because https://github.com/flutter/flutter/issues/118401
slugify: ^2.0.0
sqflite_common_ffi: ^2.3.6