Notifications (android via local) work

This commit is contained in:
2024-06-15 21:29:51 +02:00
parent e6fbf85e6e
commit e9ea573e33
39 changed files with 476 additions and 104 deletions

View File

@@ -3,7 +3,7 @@ import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:simplecloudnotifier/api/api_client.dart';
import 'package:simplecloudnotifier/models/channel.dart';
import 'package:simplecloudnotifier/models/message.dart';
import 'package:simplecloudnotifier/models/scn_message.dart';
import 'package:simplecloudnotifier/state/app_auth.dart';
class ChannelListItem extends StatefulWidget {
@@ -23,7 +23,7 @@ class ChannelListItem extends StatefulWidget {
}
class _ChannelListItemState extends State<ChannelListItem> {
Message? lastMessage;
SCNMessage? lastMessage;
@override
void initState() {

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:simplecloudnotifier/utils/notifier.dart';
import 'package:simplecloudnotifier/utils/toaster.dart';
import 'package:simplecloudnotifier/utils/ui.dart';
@@ -52,6 +53,12 @@ class _DebugActionsPageState extends State<DebugActionsPage> {
onPressed: _sendTokenToServer,
text: 'Send FCM Token to Server',
),
SizedBox(height: 20),
UI.button(
big: false,
onPressed: () => Notifier.showLocalNotification('TEST_CHANNEL', "Test Channel", "Channel for testing", "Hello World", "Local Notification test", null),
text: 'Show local notification',
),
],
),
),

View File

@@ -30,7 +30,6 @@ class _DebugMainPageState extends State<DebugMainPage> {
return SCNScaffold(
title: 'Debug',
showSearch: false,
showDebug: false,
child: Column(
children: [
Padding(

View File

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:simplecloudnotifier/models/channel.dart';
import 'package:simplecloudnotifier/models/message.dart';
import 'package:simplecloudnotifier/models/scn_message.dart';
import 'package:simplecloudnotifier/pages/debug/debug_persistence_hive.dart';
import 'package:simplecloudnotifier/pages/debug/debug_persistence_sharedprefs.dart';
import 'package:simplecloudnotifier/state/application_log.dart';
@@ -36,7 +36,7 @@ class _DebugPersistencePageState extends State<DebugPersistencePage> {
_buildSharedPrefCard(context),
_buildHiveCard(context, () => Hive.box<SCNRequest>('scn-requests'), 'scn-requests'),
_buildHiveCard(context, () => Hive.box<SCNLog>('scn-logs'), 'scn-logs'),
_buildHiveCard(context, () => Hive.box<Message>('scn-message-cache'), 'scn-message-cache'),
_buildHiveCard(context, () => Hive.box<SCNMessage>('scn-message-cache'), 'scn-message-cache'),
_buildHiveCard(context, () => Hive.box<Channel>('scn-channel-cache'), 'scn-channel-cache'),
_buildHiveCard(context, () => Hive.box<FBMessage>('scn-fb-messages'), 'scn-fb-messages'),
],
@@ -71,7 +71,7 @@ class _DebugPersistencePageState extends State<DebugPersistencePage> {
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () {
Navi.push(context, () => DebugHiveBoxPage(boxName: boxname, box: Hive.box<FBMessage>(boxname)));
Navi.push(context, () => DebugHiveBoxPage(boxName: boxname, box: boxFunc()));
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,

View File

@@ -16,7 +16,6 @@ class DebugHiveBoxPage extends StatelessWidget {
return SCNScaffold(
title: 'Hive: ' + boxName,
showSearch: false,
showDebug: false,
child: ListView.separated(
itemCount: box.length,
itemBuilder: (context, listIndex) {
@@ -24,8 +23,9 @@ class DebugHiveBoxPage extends StatelessWidget {
onTap: () {
Navi.push(context, () => DebugHiveEntryPage(value: box.getAt(listIndex)!));
},
child: ListTile(
title: Text(box.getAt(listIndex).toString(), style: TextStyle(fontWeight: FontWeight.bold)),
child: Container(
padding: EdgeInsets.fromLTRB(8, 4, 8, 4),
child: Text(box.getAt(listIndex).toString(), style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12)),
),
);
},

View File

@@ -13,11 +13,13 @@ class DebugHiveEntryPage extends StatelessWidget {
return SCNScaffold(
title: 'HiveEntry',
showSearch: false,
showDebug: false,
child: ListView.separated(
itemCount: fields.length,
itemBuilder: (context, listIndex) {
return ListTile(
dense: true,
contentPadding: EdgeInsets.fromLTRB(8, 0, 8, 0),
visualDensity: VisualDensity(horizontal: 0, vertical: -4),
title: Text(fields[listIndex].$1, style: TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text(fields[listIndex].$2, style: TextStyle(fontFamily: "monospace")),
);

View File

@@ -13,7 +13,6 @@ class DebugSharedPrefPage extends StatelessWidget {
return SCNScaffold(
title: 'SharedPreferences',
showSearch: false,
showDebug: false,
child: ListView.separated(
itemCount: sharedPref.getKeys().length,
itemBuilder: (context, listIndex) {

View File

@@ -16,7 +16,6 @@ class DebugRequestViewPage extends StatelessWidget {
return SCNScaffold(
title: 'Request',
showSearch: false,
showDebug: false,
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),

View File

@@ -4,8 +4,9 @@ import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:provider/provider.dart';
import 'package:simplecloudnotifier/api/api_client.dart';
import 'package:simplecloudnotifier/models/channel.dart';
import 'package:simplecloudnotifier/models/message.dart';
import 'package:simplecloudnotifier/models/scn_message.dart';
import 'package:simplecloudnotifier/pages/message_view/message_view.dart';
import 'package:simplecloudnotifier/settings/app_settings.dart';
import 'package:simplecloudnotifier/state/app_bar_state.dart';
import 'package:simplecloudnotifier/state/application_log.dart';
import 'package:simplecloudnotifier/state/app_auth.dart';
@@ -25,11 +26,9 @@ class MessageListPage extends StatefulWidget {
}
class _MessageListPageState extends State<MessageListPage> with RouteAware {
static const _pageSize = 128;
late final AppLifecycleListener _lifecyleListener;
PagingController<String, Message> _pagingController = PagingController.fromValue(PagingState(nextPageKey: null, itemList: [], error: null), firstPageKey: '@start');
PagingController<String, SCNMessage> _pagingController = PagingController.fromValue(PagingState(nextPageKey: null, itemList: [], error: null), firstPageKey: '@start');
Map<String, Channel>? _channels = null;
@@ -65,7 +64,7 @@ class _MessageListPageState extends State<MessageListPage> with RouteAware {
ApplicationLog.debug('MessageListPage::_realInitState');
final chnCache = Hive.box<Channel>('scn-channel-cache');
final msgCache = Hive.box<Message>('scn-message-cache');
final msgCache = Hive.box<SCNMessage>('scn-message-cache');
if (chnCache.isNotEmpty && msgCache.isNotEmpty) {
// ==== Use cache values - and refresh in background
@@ -119,6 +118,7 @@ class _MessageListPageState extends State<MessageListPage> with RouteAware {
Future<void> _fetchPage(String thisPageToken) async {
final acc = Provider.of<AppAuth>(context, listen: false);
final cfg = Provider.of<AppSettings>(context, listen: false);
ApplicationLog.debug('Start MessageList::_pagingController::_fetchPage [ ${thisPageToken} ]');
@@ -135,7 +135,7 @@ class _MessageListPageState extends State<MessageListPage> with RouteAware {
_setChannelCache(channels); // no await
}
final (npt, newItems) = await APIClient.getMessageList(acc, thisPageToken, pageSize: _pageSize);
final (npt, newItems) = await APIClient.getMessageList(acc, thisPageToken, pageSize: cfg.messagePageSize);
_addToMessageCache(newItems); // no await
@@ -154,6 +154,7 @@ class _MessageListPageState extends State<MessageListPage> with RouteAware {
Future<void> _backgroundRefresh(bool fullReplaceState) async {
final acc = Provider.of<AppAuth>(context, listen: false);
final cfg = Provider.of<AppSettings>(context, listen: false);
ApplicationLog.debug('Start background refresh of message list (fullReplaceState: $fullReplaceState)');
@@ -170,7 +171,7 @@ class _MessageListPageState extends State<MessageListPage> with RouteAware {
_setChannelCache(channels); // no await
}
final (npt, newItems) = await APIClient.getMessageList(acc, '@start', pageSize: _pageSize);
final (npt, newItems) = await APIClient.getMessageList(acc, '@start', pageSize: cfg.messagePageSize);
_addToMessageCache(newItems); // no await
@@ -225,9 +226,9 @@ class _MessageListPageState extends State<MessageListPage> with RouteAware {
onRefresh: () => Future.sync(
() => _pagingController.refresh(),
),
child: PagedListView<String, Message>(
child: PagedListView<String, SCNMessage>(
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<Message>(
builderDelegate: PagedChildBuilderDelegate<SCNMessage>(
itemBuilder: (context, item, index) => MessageListItem(
message: item,
allChannels: _channels ?? {},
@@ -249,20 +250,22 @@ class _MessageListPageState extends State<MessageListPage> with RouteAware {
for (var chn in channels) await cache.put(chn.channel.channelID, chn.channel);
}
Future<void> _addToMessageCache(List<Message> newItems) async {
final cache = Hive.box<Message>('scn-message-cache');
Future<void> _addToMessageCache(List<SCNMessage> newItems) async {
final cfg = AppSettings();
final cache = Hive.box<SCNMessage>('scn-message-cache');
for (var msg in newItems) await cache.put(msg.messageID, msg);
// delete all but the newest 128 messages
if (cache.length < _pageSize) return;
if (cache.length < cfg.messagePageSize) return;
final allValues = cache.values.toList();
allValues.sort((a, b) => -1 * a.timestamp.compareTo(b.timestamp));
for (var val in allValues.sublist(_pageSize)) {
for (var val in allValues.sublist(cfg.messagePageSize)) {
await cache.delete(val.messageID);
}
}

View File

@@ -3,7 +3,7 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:simplecloudnotifier/models/channel.dart';
import 'package:simplecloudnotifier/models/message.dart';
import 'package:simplecloudnotifier/models/scn_message.dart';
import 'package:intl/intl.dart';
import 'package:simplecloudnotifier/utils/ui.dart';
@@ -18,7 +18,7 @@ class MessageListItem extends StatelessWidget {
super.key,
});
final Message message;
final SCNMessage message;
final Map<String, Channel> allChannels;
final Null Function() onPressed;
@@ -176,11 +176,11 @@ class MessageListItem extends StatelessWidget {
return v;
}
String resolveChannelName(Message message) {
String resolveChannelName(SCNMessage message) {
return allChannels[message.channelID]?.displayName ?? message.channelInternalName;
}
bool showChannel(Message message) {
bool showChannel(SCNMessage message) {
return message.channelInternalName != 'main';
}
}

View File

@@ -8,7 +8,7 @@ import 'package:simplecloudnotifier/api/api_client.dart';
import 'package:simplecloudnotifier/components/layout/scaffold.dart';
import 'package:simplecloudnotifier/models/channel.dart';
import 'package:simplecloudnotifier/models/keytoken.dart';
import 'package:simplecloudnotifier/models/message.dart';
import 'package:simplecloudnotifier/models/scn_message.dart';
import 'package:simplecloudnotifier/models/user.dart';
import 'package:simplecloudnotifier/state/app_auth.dart';
import 'package:simplecloudnotifier/state/app_bar_state.dart';
@@ -18,15 +18,15 @@ import 'package:simplecloudnotifier/utils/ui.dart';
class MessageViewPage extends StatefulWidget {
const MessageViewPage({super.key, required this.message});
final Message message; // Potentially trimmed
final SCNMessage message; // Potentially trimmed
@override
State<MessageViewPage> createState() => _MessageViewPageState();
}
class _MessageViewPageState extends State<MessageViewPage> {
late Future<(Message, ChannelPreview, KeyTokenPreview, UserPreview)>? mainFuture;
(Message, ChannelPreview, KeyTokenPreview, UserPreview)? mainFutureSnapshot = null;
late Future<(SCNMessage, ChannelPreview, KeyTokenPreview, UserPreview)>? mainFuture;
(SCNMessage, ChannelPreview, KeyTokenPreview, UserPreview)? mainFutureSnapshot = null;
static final _dateFormat = DateFormat('yyyy-MM-dd kk:mm');
bool _monospaceMode = false;
@@ -37,7 +37,7 @@ class _MessageViewPageState extends State<MessageViewPage> {
super.initState();
}
Future<(Message, ChannelPreview, KeyTokenPreview, UserPreview)> fetchData() async {
Future<(SCNMessage, ChannelPreview, KeyTokenPreview, UserPreview)> fetchData() async {
try {
await Future.delayed(const Duration(seconds: 0), () {}); // this is annoyingly important - otherwise we call setLoadingIndeterminate directly in initStat() and get an exception....
@@ -79,7 +79,7 @@ class _MessageViewPageState extends State<MessageViewPage> {
showSearch: false,
showShare: true,
onShare: _share,
child: FutureBuilder<(Message, ChannelPreview, KeyTokenPreview, UserPreview)>(
child: FutureBuilder<(SCNMessage, ChannelPreview, KeyTokenPreview, UserPreview)>(
future: mainFuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
@@ -118,7 +118,7 @@ class _MessageViewPageState extends State<MessageViewPage> {
}
}
Widget _buildMessageView(BuildContext context, Message message, ChannelPreview? channel, KeyTokenPreview? token, UserPreview? user) {
Widget _buildMessageView(BuildContext context, SCNMessage message, ChannelPreview? channel, KeyTokenPreview? token, UserPreview? user) {
final userAccUserID = context.select<AppAuth, String?>((v) => v.userID);
return SingleChildScrollView(
@@ -144,11 +144,11 @@ class _MessageViewPageState extends State<MessageViewPage> {
);
}
String _resolveChannelName(ChannelPreview? channel, Message message) {
String _resolveChannelName(ChannelPreview? channel, SCNMessage message) {
return channel?.displayName ?? message.channelInternalName;
}
List<Widget> _buildMessageHeader(BuildContext context, Message message, ChannelPreview? channel) {
List<Widget> _buildMessageHeader(BuildContext context, SCNMessage message, ChannelPreview? channel) {
return [
Row(
children: [
@@ -167,7 +167,7 @@ class _MessageViewPageState extends State<MessageViewPage> {
];
}
List<Widget> _buildMessageContent(BuildContext context, Message message) {
List<Widget> _buildMessageContent(BuildContext context, SCNMessage message) {
return [
Row(
children: [
@@ -249,7 +249,7 @@ class _MessageViewPageState extends State<MessageViewPage> {
}
}
String _preformatTitle(Message message) {
String _preformatTitle(SCNMessage message) {
return message.title.replaceAll('\n', '').replaceAll('\r', '').replaceAll('\t', ' ');
}
}