add fastlane data and github action

This commit is contained in:
otsmr 2025-07-18 20:29:45 +02:00
parent c18a8ed311
commit 0fae906852
22 changed files with 99 additions and 14 deletions

1
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1 @@
github: otsmr

58
.github/workflows/release_github.yml vendored Normal file
View file

@ -0,0 +1,58 @@
name: Github Release
on:
push:
tags:
- "v*.*.*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v4
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
- run: flutter pub get
- run: flutter analyze
- run: flutter test
- name: Create key.properties file
run: |
echo "storePassword=${{ secrets.STORE_PASSWORD }}" >> ./android/key.properties
echo "keyPassword=${{ secrets.ALIAS_PASSWORD }}" >> ./android/key.properties
echo "keyAlias=androidreleasekey" >> key.properties
echo "storeFile=./android/keystore.jks" >> ./android/key.properties
run: base64 -d <<< $KEYSTORE_FILE > ./android/keystore.jks
- name: Build Android APK
- run: flutter build apk --release --split-per-abi
- name: Create Github Release
- uses: actions/upload-artifact@v4
with:
name: release-apk
path: build/app/outputs/flutter-apk/*.apk
- name: Generate Checksums
run: |
tree .
find app -type f -exec md5sum {} \; >> RELEASE.md5sum
find app -type f -exec sha256sum {} \; >> RELEASE.sha256sum
sed -i 's|app/.*/\([^/]*\)$|\1|' RELEASE.sha256sum RELEASE.md5sum
sed -i 's|app/||' RELEASE.sha256sum RELEASE.md5sum
- name: Upload Release Binaries (stable)
if: ${{ !inputs.dry_run && inputs.channel == 'stable' }}
uses: ncipollo/release-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag: v${{ env.PUBSPEC_VERSION }} # mind the "v" prefix
omitBodyDuringUpdate: true
omitNameDuringUpdate: true
omitPrereleaseDuringUpdate: true
allowUpdates: true
artifacts: app_*/**/*,RELEASE.sha256sum,RELEASE.md5sum

View file

@ -1,9 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:cryptography_plus/cryptography_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
@ -16,7 +12,6 @@ import 'package:twonly/src/views/components/app_outdated.dart';
import 'package:twonly/src/views/home.view.dart'; import 'package:twonly/src/views/home.view.dart';
import 'package:twonly/src/views/onboarding/onboarding.view.dart'; import 'package:twonly/src/views/onboarding/onboarding.view.dart';
import 'package:twonly/src/views/onboarding/register.view.dart'; import 'package:twonly/src/views/onboarding/register.view.dart';
import 'package:twonly/src/views/settings/help/changelog.view.dart';
class App extends StatefulWidget { class App extends StatefulWidget {
const App({super.key}); const App({super.key});

View file

@ -17,6 +17,7 @@ class ConnectSignedPreKeyStore extends SignedPreKeyStore {
} }
final storeHashMap = json.decode(storeSerialized) as List<dynamic>; final storeHashMap = json.decode(storeSerialized) as List<dynamic>;
for (final item in storeHashMap) { for (final item in storeHashMap) {
// ignore: avoid_dynamic_calls
store[item[0] as int] = base64Decode(item[1] as String); store[item[0] as int] = base64Decode(item[1] as String);
} }
return store; return store;

View file

@ -9,7 +9,7 @@ class ChatDateChip extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var formattedDate = item.isTime final formattedDate = item.isTime
? DateFormat.Hm(Localizations.localeOf(context).toLanguageTag()) ? DateFormat.Hm(Localizations.localeOf(context).toLanguageTag())
.format(item.time!) .format(item.time!)
: '${DateFormat.Hm(Localizations.localeOf(context).toLanguageTag()).format(item.date!)} ${DateFormat.yMd(Localizations.localeOf(context).toLanguageTag()).format(item.date!)}'; : '${DateFormat.Hm(Localizations.localeOf(context).toLanguageTag()).format(item.date!)} ${DateFormat.yMd(Localizations.localeOf(context).toLanguageTag()).format(item.date!)}';

View file

@ -119,7 +119,7 @@ class _MemoriesPhotoSliderViewState extends State<MemoriesPhotoSliderView> {
alignment: Alignment.bottomRight, alignment: Alignment.bottomRight,
children: <Widget>[ children: <Widget>[
MediaViewSizing( MediaViewSizing(
bottomNavigation: Container( bottomNavigation: ColoredBox(
color: context.color.surface, color: context.color.surface,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,

View file

@ -4,7 +4,7 @@ import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/utils/storage.dart';
List<Widget> parseMarkdown(BuildContext context, String markdown) { List<Widget> parseMarkdown(BuildContext context, String markdown) {
List<Widget> widgets = []; final widgets = <Widget>[];
// Split the string into lines // Split the string into lines
final lines = markdown.split('\n'); final lines = markdown.split('\n');
@ -37,7 +37,7 @@ List<Widget> parseMarkdown(BuildContext context, String markdown) {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: EdgeInsets.only(top: 7), padding: const EdgeInsets.only(top: 7),
child: Icon( child: Icon(
Icons.brightness_1, Icons.brightness_1,
size: 7, size: 7,

View file

@ -102,7 +102,7 @@ class HelpView extends StatelessWidget {
}, },
), ),
ListTile( ListTile(
title: const Text("Open Source"), title: const Text('Open Source'),
onTap: () { onTap: () {
launchUrl(Uri.parse('https://github.com/twonlyapp/twonly-app')); launchUrl(Uri.parse('https://github.com/twonlyapp/twonly-app'));
}, },
@ -127,17 +127,17 @@ class HelpView extends StatelessWidget {
), ),
ListTile( ListTile(
onLongPress: () async { onLongPress: () async {
bool? okay = await showAlertDialog( final okay = await showAlertDialog(
context, context,
"Delete Retransmission messages", 'Delete Retransmission messages',
"Only do this if you know what you are doing :)", 'Only do this if you know what you are doing :)',
); );
if (okay == true) { if (okay == true) {
await twonlyDB.messageRetransmissionDao await twonlyDB.messageRetransmissionDao
.clearRetransmissionTable(); .clearRetransmissionTable();
} }
}, },
title: Text( title: const Text(
'Copyright twonly', 'Copyright twonly',
style: TextStyle(color: Colors.grey, fontSize: 13), style: TextStyle(color: Colors.grey, fontSize: 13),
), ),

View file

@ -0,0 +1,13 @@
twonly, eine datenschutzfreundliche Möglichkeit sich mit Freunden durch sichere, spontane Bildübertragung zu verbinden.
=> Unbeschwertes Teilen <=
Mit Ende-zu-Ende-Verschlüsselung genieße die Gewissheit, dass nur du und deine Freunde die Momente sehen können, die du teilst.
=> Konzentriere dich auf das Teilen von Momenten <=
Verabschiede dich von süchtig machenden Funktionen! twonly wurde für das Teilen von Momenten geschaffen, frei von nutzlosen Ablenkungen oder Werbung.
=> In Europa ansässig <=
twonly wird ausschließlich in Europa entwickelt und gehostet. Erstellt von einem Studenten, nicht von einem großen Tech-Unternehmen, das deine persönlichen Daten zum Profit verkauft.
=> Du bist nicht das Produkt! <=
twonly wird klar und transparent durch eine monatliche Gebühr finanziert und nicht durch den Verkauf deiner Daten.

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

View file

@ -0,0 +1 @@
Privat in Kontakt bleiben.

1
metadata/de-DE/title.txt Normal file
View file

@ -0,0 +1 @@
twonly

View file

@ -0,0 +1,13 @@
twonly, a privacy-friendly way to connect with friends through secure, spontaneous image sharing.
=> Carefree sharing <=
With end-to-end encryption, enjoy the peace of mind that only you and your friends can see the moments you share.
=> Focus on sharing moments <=
Say goodbye to addictive features! twonly was created for sharing moments, free from useless distractions or ads.
=> Based in Europe <=
twonly is developed and hosted exclusively in Europe. Created by a student, not a big tech company selling your personal data for profit.
=> You are not the product! <=
twonly is clearly and transparently funded by a monthly fee and not by selling your data.

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

View file

@ -0,0 +1 @@
Stay in touch privately.

1
metadata/en-US/title.txt Normal file
View file

@ -0,0 +1 @@
twonly