improve onboarding
33
README.md
|
|
@ -2,6 +2,39 @@
|
||||||
|
|
||||||
Don't be lonely, get twonly! Send pictures to a friend in real time and be sure you are the only two people who can see them.
|
Don't be lonely, get twonly! Send pictures to a friend in real time and be sure you are the only two people who can see them.
|
||||||
|
|
||||||
|
|
||||||
|
## TODOS bevor first beta
|
||||||
|
- Flammen Problem fixen
|
||||||
|
- Add no_screenshot plugin: https://pub.dev/packages/no_screenshot
|
||||||
|
- Bei mehreren neu Empfangen Nachrichten fixen
|
||||||
|
- Settings
|
||||||
|
- Delete and Block active users
|
||||||
|
- Onboarding Slide, Text und Animationen
|
||||||
|
- MessageKind -> Ausbauen?
|
||||||
|
- Nachrichten nach 24h Stunden löschen
|
||||||
|
- Real deployment aufsetzen direkt auf Netcup?
|
||||||
|
- Pro Invitation codes
|
||||||
|
|
||||||
|
## Later todos
|
||||||
|
- Videos
|
||||||
|
- Sealed Sender
|
||||||
|
- Settings
|
||||||
|
- Profilbilder erstellen.
|
||||||
|
- Pro Version
|
||||||
|
- Media Shower -> Recap of the day
|
||||||
|
- Send normal images via twonly
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Pro Version
|
||||||
|
|
||||||
|
- Send and receive unlimited pictures
|
||||||
|
- This includes a free pro version for your twonly partner!
|
||||||
|
- Get up to 3 tokens
|
||||||
|
- Get for your twonly partner a second a additional pro version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
This app was started because of the three main features I missed out by popular alternatives.
|
This app was started because of the three main features I missed out by popular alternatives.
|
||||||
|
|
|
||||||
1
assets/animations/e2e.json
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{"v":"4.8.0","meta":{"g":"LottieFiles AE 3.0.2","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":77,"w":500,"h":500,"nm":"security tick","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"tick","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.094,0.094,0.094],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.067,0.067,-0.067]},"t":32,"s":[62,62,100]},{"t":56,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.947,0],[-17.649,35.298],[52.947,-35.298]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":25.537,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.178],"y":[1]},"o":{"x":[0.21],"y":[0]},"t":32,"s":[0]},{"t":62,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"shield","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":4,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.97],"y":[1]},"o":{"x":[0.03],"y":[0]},"t":0,"s":[250]},{"i":{"x":[0.97],"y":[1]},"o":{"x":[0.03],"y":[0]},"t":20,"s":[250]},{"t":40,"s":[250]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.174],"y":[0.822]},"t":0,"s":[319]},{"i":{"x":[0.334],"y":[1]},"o":{"x":[0.308],"y":[0]},"t":20,"s":[197]},{"t":40,"s":[250]}],"ix":4}},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.174,0.174,0.174],"y":[0.822,0.822,-0.822]},"t":0,"s":[46,46,100]},{"t":20,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.094,"y":1},"o":{"x":0.252,"y":0},"t":25,"s":[{"i":[[-29.271,0],[0,-29.271],[29.271,0],[0,29.271]],"o":[[29.271,0],[0,29.271],[-29.271,0],[0,-29.271]],"v":[[0,-53],[53,0],[0,53],[-53,0]],"c":true}]},{"t":56,"s":[{"i":[[-2.504,1.787],[-85.122,-7.093],[120.419,-40.532],[0,158.319]],"o":[[2.504,1.787],[0,158.319],[-120.419,-40.532],[85.122,-7.093]],"v":[[0,-169.229],[141.87,-126.668],[0,169.229],[-141.87,-126.668]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.360784322023,0.800000011921,0.474509805441,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0}],"markers":[]}
|
||||||
1
assets/animations/local.json
Normal file
1
assets/animations/messages.json
Normal file
BIN
assets/animations/messages.lottie
Normal file
1
assets/animations/product.json
Normal file
1
assets/animations/rocket.json
Normal file
1
assets/animations/selfie.json
Normal file
1
assets/animations/selfie2.json
Normal file
1
assets/animations/test.json
Normal file
1
assets/animations/twonlies.json
Normal file
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 307 KiB |
|
Before Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 581 KiB |
|
Before Width: | Height: | Size: 514 KiB |
|
Before Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 219 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 83 KiB |
|
|
@ -35,7 +35,7 @@ class MyApp extends StatefulWidget {
|
||||||
|
|
||||||
class _MyAppState extends State<MyApp> {
|
class _MyAppState extends State<MyApp> {
|
||||||
Future<bool> _isUserCreated = isUserCreated();
|
Future<bool> _isUserCreated = isUserCreated();
|
||||||
bool _showOnboarding = false;
|
bool _showOnboarding = true;
|
||||||
bool _isConnected = false;
|
bool _isConnected = false;
|
||||||
int redColorOpacity = 0; // Start with dark red
|
int redColorOpacity = 0; // Start with dark red
|
||||||
bool redColorGoUp = true;
|
bool redColorGoUp = true;
|
||||||
|
|
|
||||||
|
|
@ -346,6 +346,11 @@ class DbMessages extends CvModelBase {
|
||||||
dynamic messageOpenedAt = fromDb[i][columnMessageOpenedAt];
|
dynamic messageOpenedAt = fromDb[i][columnMessageOpenedAt];
|
||||||
if (messageOpenedAt != null) {
|
if (messageOpenedAt != null) {
|
||||||
messageOpenedAt = DateTime.tryParse(fromDb[i][columnMessageOpenedAt]);
|
messageOpenedAt = DateTime.tryParse(fromDb[i][columnMessageOpenedAt]);
|
||||||
|
// if (messageOpenedAt != null) {
|
||||||
|
// if (messageOpenedAt.difference()) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
int? messageOtherId = fromDb[i][columnMessageOtherId];
|
int? messageOtherId = fromDb[i][columnMessageOtherId];
|
||||||
MessageContent content = MessageContent.fromJson(
|
MessageContent content = MessageContent.fromJson(
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,8 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Lottie.asset(
|
child: Lottie.asset(
|
||||||
'assets/animations/present.lottie.json'),
|
'assets/animations/present.lottie.json',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.only(bottom: 200),
|
padding: EdgeInsets.only(bottom: 200),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,22 @@
|
||||||
import 'package:introduction_screen/introduction_screen.dart';
|
import 'package:introduction_screen/introduction_screen.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lottie/lottie.dart';
|
||||||
|
|
||||||
|
// Slide 1: Welcome to [App Name]
|
||||||
|
// Text: "Experience a new way to connect with friends through secure, spontaneous image sharing."
|
||||||
|
// Image Idea: A vibrant, welcoming graphic featuring diverse groups of friends using the app in various settings (e.g., at a café, at a party, etc.).
|
||||||
|
|
||||||
|
// Slide 2: End-to-End Encryption
|
||||||
|
// Text: "Your privacy matters. Enjoy peace of mind with end-to-end encryption, ensuring only you and your friends can see your images."
|
||||||
|
// Image Idea: A lock symbol overlaying a smartphone screen displaying an encrypted message, symbolizing security and privacy.
|
||||||
|
|
||||||
|
// Slide 3: Local Processing
|
||||||
|
// Text: "Everything is done locally. Our servers only see encrypted bytes, keeping your data safe from prying eyes."
|
||||||
|
// Image Idea: A visual representation of local processing, such as a smartphone with a shield icon, indicating that data remains on the device.
|
||||||
|
|
||||||
|
// Slide 4: Focus on Images
|
||||||
|
// Text: "Say goodbye to clutter! Our app is designed for sharing images, not useless distractions."
|
||||||
|
// Image Idea: A clean, minimalist interface showcasing a user effortlessly sending an image, with a focus on the image itself.
|
||||||
|
|
||||||
class OnboardingView extends StatelessWidget {
|
class OnboardingView extends StatelessWidget {
|
||||||
const OnboardingView({super.key, required this.callbackOnSuccess});
|
const OnboardingView({super.key, required this.callbackOnSuccess});
|
||||||
|
|
@ -14,60 +31,93 @@ class OnboardingView extends StatelessWidget {
|
||||||
PageViewModel(
|
PageViewModel(
|
||||||
title: "Welcome to twonly!",
|
title: "Welcome to twonly!",
|
||||||
body:
|
body:
|
||||||
"With twonly you can share pictures with friends that only you and the receiver can see!",
|
"Experience a new way to connect with friends through secure, spontaneous image sharing.",
|
||||||
image: Center(
|
image: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(top: 100),
|
padding: const EdgeInsets.only(top: 100),
|
||||||
child: Image.asset("assets/images/onboarding/01.png"),
|
// child: Image.asset('assets/animations/messages.gif'),
|
||||||
|
child: Lottie.asset(
|
||||||
|
'assets/animations/messages.json',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PageViewModel(
|
PageViewModel(
|
||||||
title: "No ads, no tracking",
|
title: "End-to-End Encryption",
|
||||||
body:
|
body:
|
||||||
"twonly is complete add free and does not collect any personal data. The server does not save any data of you.",
|
"Your privacy matters. Enjoy peace of mind with end-to-end encryption, ensuring only you and your friends can see your images.",
|
||||||
image: Center(
|
image: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(top: 100),
|
padding: const EdgeInsets.only(top: 100),
|
||||||
child: Image.asset("assets/images/onboarding/02.png"),
|
child: Lottie.asset(
|
||||||
|
'assets/animations/e2e.json',
|
||||||
|
repeat: false,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PageViewModel(
|
PageViewModel(
|
||||||
title: "End-to-End protection",
|
title: "Focus on sharing moments",
|
||||||
body:
|
body:
|
||||||
"twonly encrypts every message you send. For this it uses the Signal protocol which is currently the best way to encrypt messages with a minimum of metadata.",
|
"Say goodbye to addictive features! Our app is designed for sharing moments, no useless distractions or ads.",
|
||||||
image: Center(
|
image: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(top: 100),
|
padding: const EdgeInsets.only(top: 100),
|
||||||
child: Image.asset("assets/images/onboarding/03.png"),
|
child: Lottie.asset(
|
||||||
|
'assets/animations/selfie2.json',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PageViewModel(
|
||||||
|
title: "Send twonlies",
|
||||||
|
body:
|
||||||
|
"Share moments securely with just one other person. twonly ensures that only you and your chosen friend can view the picture, keeping your moments private.",
|
||||||
|
image: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 100),
|
||||||
|
child: Lottie.asset(
|
||||||
|
'assets/animations/twonlies.json',
|
||||||
|
repeat: false,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// PageViewModel(
|
|
||||||
// title: "Hard work",
|
|
||||||
// body:
|
|
||||||
// "We try everything to give you the best experience but developing and maintaining is hard work and requires thousand of hours.",
|
|
||||||
// image: Center(
|
|
||||||
// child: Padding(
|
|
||||||
// padding: const EdgeInsets.only(top: 100),
|
|
||||||
// child: Image.asset("assets/images/onboarding/04.png"),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
PageViewModel(
|
PageViewModel(
|
||||||
title: "You are not the product!",
|
title: "You are not the product!",
|
||||||
body:
|
body:
|
||||||
"Nothing is free. Either you pay with your personal informations or with money. Twonly gives you the chance to use an social media product without exploiting you by collection you personal data.",
|
"If you don't pay, your data is the product that is sold. So we decided to develop a sustainable business model where everyone wins. You can keep your data private and we can create a beautiful app.",
|
||||||
image: Center(
|
image: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(top: 100),
|
padding: const EdgeInsets.only(top: 100),
|
||||||
child: Image.asset("assets/images/onboarding/05.png"),
|
child: Lottie.asset(
|
||||||
|
'assets/animations/product.json',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PageViewModel(
|
PageViewModel(
|
||||||
title: "Try for free!",
|
title: "Pricing",
|
||||||
|
bodyWidget: Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"To be able to create a sustainable privacy focused app which does not show ads, we have to rely on you! You can get twonly for only 0,99€ / monthly or 9,99€ / yearly. As twonly is for at least two, you get a second user for free, so your twonly partner does not have to pay!",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
image: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 100),
|
||||||
|
child: Lottie.asset(
|
||||||
|
'assets/animations/selfie.json',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PageViewModel(
|
||||||
|
title: "Let's get started!",
|
||||||
bodyWidget: Column(
|
bodyWidget: Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -90,7 +140,9 @@ class OnboardingView extends StatelessWidget {
|
||||||
image: Center(
|
image: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(top: 100),
|
padding: const EdgeInsets.only(top: 100),
|
||||||
child: Image.asset("assets/images/onboarding/06.png"),
|
child: Lottie.asset(
|
||||||
|
'assets/animations/rocket.json',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
16
pubspec.yaml
|
|
@ -75,11 +75,11 @@ flutter:
|
||||||
# Add assets from the images directory to the application.
|
# Add assets from the images directory to the application.
|
||||||
- assets/images/
|
- assets/images/
|
||||||
- assets/animations/present.lottie.json
|
- assets/animations/present.lottie.json
|
||||||
- assets/icons/
|
- assets/animations/selfie2.json
|
||||||
- assets/icons/flame.png
|
- assets/animations/messages.json
|
||||||
- assets/images/onboarding/01.png
|
- assets/animations/local.json
|
||||||
- assets/images/onboarding/02.png
|
- assets/animations/test.json
|
||||||
- assets/images/onboarding/03.png
|
- assets/animations/product.json
|
||||||
- assets/images/onboarding/04.png
|
- assets/animations/twonlies.json
|
||||||
- assets/images/onboarding/05.png
|
- assets/animations/rocket.json
|
||||||
- assets/images/onboarding/06.png
|
- assets/animations/e2e.json
|
||||||
|
|
|
||||||