Skip to content

Commit

Permalink
added initial support for incoming inbox feature, changes to readme, …
Browse files Browse the repository at this point in the history
…and adjustments to compact view
  • Loading branch information
hjiangsu committed Jun 24, 2023
1 parent 1c6056f commit 2eb1d70
Show file tree
Hide file tree
Showing 22 changed files with 572 additions and 55 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
- Improved accessibility labels for icons and actions
- New compact view for posts in the feed
- New OLED black theme
- Added initial inbox feature to see your replies, mentions, and private messages
- Added about page with links to lemmy and github repository

### Fixed
- Potentially fixed issue where scrolling behaviour is weird when creating a new post or comment
Expand Down
79 changes: 53 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</h4>

<p align="center">
<a href="">
<a href="https://github.com/hjiangsu/thunder/blob/main/LICENSE">
<img src="https://img.shields.io/github/license/hjiangsu/thunder" alt="License">
</a>
<a href="">
Expand All @@ -23,11 +23,15 @@
<a href="">
<img src="https://img.shields.io/badge/platform-ios%20%7C%20android-blueviolet" alt="Platforms">
</a>
<a href="">
<img src="https://img.shields.io/github/v/release/hjiangsu/thunder" alt="Latest Release">
</a>

</p>

<p align="center">
<a href="https://github.com/hjiangsu/thunder/releases">
<img src="https://img.shields.io/github/v/release/hjiangsu/thunder?label=latest release" alt="Latest Release">
</a>
<a href="https://apt.izzysoft.de/fdroid/index/apk/com.hjiangsu.thunder">
<img src="https://img.shields.io/endpoint?url=https://apt.izzysoft.de/fdroid/api/v1/shield/com.hjiangsu.thunder" alt="IzzyOnDroid">
</a>
</p>

<p align="center">
Expand Down Expand Up @@ -56,7 +60,7 @@
Hey there! Just wanted to let you know that this repo is currently my personal side project to build something cool while learning about Dart and Flutter.
</p>
<p>
As the sole maintainer of this project, progress might be a bit slow. But hey, here's where you can make a difference! Whether you're proficient at Flutter and Dart, or just simply interested in the project, I would be absolutely thrilled if you could lend a hand and contribute.
Contributions to this project are always welcomed, and in fact, even strongly encouraged here! Since I am only able to work on this during my spare time, any contributions from the community is valuable. If you are a developer, feel free to tackle any issues present.
</p>
<p>
Your passion, contributions, and ideas would be greatly appreciated! Together, let's make this project shine. 🚀 💻
Expand All @@ -65,44 +69,59 @@ Your passion, contributions, and ideas would be greatly appreciated! Together, l


## Releases
**Note:** As this is still in alpha and WIP, releases will happen through GitHub. There are no plans at the moment to release to Google Play store (and derivatives) or Apple's TestFlight. However, this may change in the future as more progress is made.
<div align="center">
<a href="https://apt.izzysoft.de/fdroid/index/apk/com.hjiangsu.thunder">
<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" height="80">
</a>
<a href="https://github.com/hjiangsu/thunder/releases/latest"><img src="https://raw.githubusercontent.com/andOTP/andOTP/master/assets/badges/get-it-on-github.png" height="80"></a>
</div>

All releases will be held in the [Releases](https://github.com/hjiangsu/thunder/releases) section under the corresponding version.
- For iOS users, you can install Thunder using [AltStore](https://altstore.io/)
- For Android users, simply install Thunder with the provided APK file.
### Android
If you are on Android, releases are available in the [Releases](https://github.com/hjiangsu/thunder/releases) section under the corresponding version. There is also an option to obtain the release through [IzzyOnDroid](https://apt.izzysoft.de/fdroid/index/apk/com.hjiangsu.thunder) if you are interested.

### iOS
If you are on iOS, there is TestFlight available through [this link](https://testflight.apple.com/join/9n8xrqvH). An alternative is to download the corresponding IPA file in the [Releases](https://github.com/hjiangsu/thunder/releases) section and install it through [AltStore](https://altstore.io/).

## Features

Thunder is currently undergoing **active development**, and it is possible that not all features have been fully implemented at this stage. Due to this, significant breaking changes may occur between versions. The next section summarizes the features that are currently implemented.

#### **Communities**

- Browse community posts
- Search for communities from the current instance (and subscribe)
- Browse subscriptions if logged in
- Browsing through general (All/Local) feeds, as well as specific communities
- Ability to search for communities that are federated with the current instance
- See a list of subscriptions, and access their community posts and general information

#### **Posts**
#### **Posts & Comments**

- Voting and saving for posts and comments
- See a specific post and its associated comments
- Infinite scrolling for posts
- Infinite scrolling for comments
- Voting (upvote/downvote) and save actions for posts and comments
- Infinite scrolling for posts and comments
- Ability to create a new post, and reply to posts/comments

#### **Authentication**

- Multi-account login and switching
- Ability to log into multiple instances, and switch between them

#### **Theme & Customization**

- Basic settings to change the view of posts on a given community/feed
- Light and dark themes available
- Basic customization for the look of posts
- Standard/Compact views
- Toggle full image views or a compacted image view
- Toggling voting and saving actions
- Light, dark, and OLED themes available

#### **Extras**
- In-app update notifications for new releases on GitHub

## Roadmap

The current focus is to provide a MVP to be able to do basic tasks, including
- Ability to create posts and comments
- Improvements to accessibility
- Improvements to customizability of post views (compact, normal, expanded, etc)
- Inbox features (replies, mentions, private messages)
- Ability to view your inbox, and be able to mark them as read
- Ability to reply to inbox messages
- Ability to see full context of a given inbox message (navigate to post, or comment for replies and mentions)
- Improvements to accessibility services
- More customizability of post views (compact, normal, expanded, etc.)

## Contributing

Expand All @@ -116,15 +135,23 @@ Contributions are always welcome! To contribute potential features or bug-fixes:

### Installing Flutter and Related Dependencies

Thunder is developed with Flutter, and is built to support both iOS and Android.
Thunder is developed with Flutter, and is built to support both iOS and Android. There may be limited support on other platforms but is not guaranteed at this time (Linux, Windows, MacOS)

To build the app from source, a few steps are required.

1. Set up and install Flutter.
- For more information, visit https://docs.flutter.dev/get-started/install.
2. Clone this repository and fetch the dependencies using `flutter pub get`
3. Generate an empty `.env` file. The `.env` file holds any credentials. At the time of writing, en empty `.env` file with a comment is all that is required.
3. Run the build script using `dart scripts/build.dart`, which will build both the iOS and Android release versions

### Environment File
This is an example of the `.env` that can be used for Thunder.
```bash
# Sentry Credentials
SENTRY_DSN=""
```

## Conventions

While there are no specific conventions that must be followed, do try to follow best practices whenever possible.
Expand All @@ -137,4 +164,4 @@ Thunder uses the following packages and libraries under the hood. This is not an

### Custom Built Libraries

[lemmy-dart](https://github.com/hjiangsu/lemmy-dart) - custom-built Lemmy library built in Dart
[lemmy-dart](https://github.com/hjiangsu/lemmy-dart) - Custom Lemmy API library written in Dart.
11 changes: 10 additions & 1 deletion lib/account/pages/login_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class _LoginPageState extends State<LoginPage> {
child: Column(
children: <Widget>[
TextField(
autocorrect: false,
controller: _usernameTextEditingController,
autofillHints: const [AutofillHints.username],
decoration: const InputDecoration(
Expand All @@ -97,6 +98,7 @@ class _LoginPageState extends State<LoginPage> {
),
const SizedBox(height: 12.0),
TextField(
autocorrect: false,
controller: _passwordTextEditingController,
obscureText: !showPassword,
enableSuggestions: false,
Expand Down Expand Up @@ -126,6 +128,7 @@ class _LoginPageState extends State<LoginPage> {
),
const SizedBox(height: 12.0),
TextField(
autocorrect: false,
controller: _instanceTextEditingController,
inputFormatters: [LowerCaseTextFormatter()],
decoration: const InputDecoration(
Expand All @@ -138,7 +141,13 @@ class _LoginPageState extends State<LoginPage> {
),
const SizedBox(height: 32.0),
ElevatedButton(
style: ElevatedButton.styleFrom(minimumSize: const Size.fromHeight(60), backgroundColor: theme.colorScheme.primary),
style: ElevatedButton.styleFrom(
minimumSize: const Size.fromHeight(60),
backgroundColor: theme.colorScheme.primary,
textStyle: theme.textTheme.titleMedium?.copyWith(
color: theme.colorScheme.onPrimary,
),
),
onPressed: (_usernameTextEditingController.text.isNotEmpty && _passwordTextEditingController.text.isNotEmpty && _instanceTextEditingController.text.isNotEmpty)
? () {
TextInput.finishAutofillContext();
Expand Down
69 changes: 69 additions & 0 deletions lib/inbox/bloc/inbox_bloc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import 'package:bloc/bloc.dart';
import 'package:dio/dio.dart';
import 'package:equatable/equatable.dart';
import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:lemmy/lemmy.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:stream_transform/stream_transform.dart';
import 'package:thunder/account/models/account.dart';
import 'package:thunder/core/auth/helpers/fetch_account.dart';
import 'package:thunder/core/singletons/lemmy_client.dart';

part 'inbox_event.dart';
part 'inbox_state.dart';

const throttleDuration = Duration(seconds: 1);
const timeout = Duration(seconds: 3);

EventTransformer<E> throttleDroppable<E>(Duration duration) {
return (events, mapper) => droppable<E>().call(events.throttle(duration), mapper);
}

class InboxBloc extends Bloc<InboxEvent, InboxState> {
InboxBloc() : super(const InboxState()) {
on<GetInboxEvent>(
_getInboxEvent,
transformer: throttleDroppable(throttleDuration),
);
}

Future<void> _getInboxEvent(GetInboxEvent event, emit) async {
try {
emit(state.copyWith(status: InboxStatus.loading));

Account? account = await fetchActiveProfileAccount();
Lemmy lemmy = LemmyClient.instance.lemmy;

if (account?.jwt == null) {
return emit(state.copyWith(status: InboxStatus.success));
}

// Fetch all the things
PrivateMessagesResponse privateMessagesResponse = await lemmy.getPrivateMessages(
GetPrivateMessages(auth: account!.jwt!),
);

GetPersonMentionsResponse personMentions = await lemmy.getPersonMentions(GetPersonMentions(
auth: account.jwt!,
sort: CommentSortType.New,
));

GetRepliesResponse repliesResponse = await lemmy.getReplies(GetReplies(
auth: account.jwt!,
));

return emit(state.copyWith(
status: InboxStatus.success,
privateMessages: privateMessagesResponse.privateMessages,
mentions: personMentions.mentions,
replies: repliesResponse.replies,
));
} on DioException catch (e, s) {
await Sentry.captureException(e, stackTrace: s);
return emit(state.copyWith(status: InboxStatus.failure, errorMessage: e.message));
} catch (e, s) {
await Sentry.captureException(e, stackTrace: s);
return emit(state.copyWith(status: InboxStatus.failure, errorMessage: e.toString()));
}
}
}
12 changes: 12 additions & 0 deletions lib/inbox/bloc/inbox_event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
part of 'inbox_bloc.dart';

abstract class InboxEvent extends Equatable {
const InboxEvent();

@override
List<Object> get props => [];
}

class GetInboxEvent extends InboxEvent {
const GetInboxEvent();
}
39 changes: 39 additions & 0 deletions lib/inbox/bloc/inbox_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
part of 'inbox_bloc.dart';

enum InboxStatus { initial, loading, refreshing, success, empty, failure }

class InboxState extends Equatable {
const InboxState({
this.status = InboxStatus.initial,
this.errorMessage,
this.privateMessages = const [],
this.mentions = const [],
this.replies = const [],
});

final InboxStatus status;
final String? errorMessage;

final List<PrivateMessageView> privateMessages;
final List<PersonMentionView> mentions;
final List<CommentReplyView> replies;

InboxState copyWith({
required InboxStatus status,
String? errorMessage,
List<PrivateMessageView>? privateMessages,
List<PersonMentionView>? mentions,
List<CommentReplyView>? replies,
}) {
return InboxState(
status: status,
errorMessage: errorMessage ?? this.errorMessage,
privateMessages: privateMessages ?? [],
mentions: mentions ?? [],
replies: replies ?? [],
);
}

@override
List<Object?> get props => [status, errorMessage];
}
1 change: 1 addition & 0 deletions lib/inbox/inbox.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'pages/inbox_page.dart';
Loading

0 comments on commit 2eb1d70

Please sign in to comment.