/wine

Free and open source collaborative social reading platform.

Primary LanguageDartApache License 2.0Apache-2.0


A collaborative social reading platorm.

license Contributor Covenant

The idea is for users to write next branches.

This way it is possible to create an infinite amount of alternative stories (a tree of possiblities).

Features

  • login, signup and logout
  • create, update and delete a tree
  • create, update and delete a branch
  • liking and bookmarking trees
  • liking and bookmarking in branches

Screenshots

Authentication pages
Login Sign up
Home pages
Home (top trees)
Library pages
Library (trees) Library (branches)
Tree page
Tree
Branch page
Branch 1 Branch 2 Branch 3

Firebase

Option 1 (Recommended)

Make sure to follow this guide to install Firebase CLI.

Follow this guide to generate Firebase Options then rename the generated file to lib\development_firebase_options.dart for dev and/or lib\production_firebase_options.dart for prod.

You'll have to run the cli twice to generate dev and prod.

Option 2

Create file lib\development_firebase_options.dart for dev and/or lib\production_firebase_options.dart for prod then copy the following config:

development_firebase_options.dart/production_firebase_options.dart
// File generated by FlutterFire CLI.
// ignore_for_file: lines_longer_than_80_chars
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
    show defaultTargetPlatform, kIsWeb, TargetPlatform;

/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
///   options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
  /// @nodoc
  static FirebaseOptions get currentPlatform {
    if (kIsWeb) {
      return web;
    }
    // ignore: missing_enum_constant_in_switch
    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
        return android;
      case TargetPlatform.iOS:
        return ios;
      case TargetPlatform.macOS:
        throw UnsupportedError(
          'DefaultFirebaseOptions have not been configured for macos - '
          'you can reconfigure this by running the FlutterFire CLI again.',
        );
    }

    throw UnsupportedError(
      'DefaultFirebaseOptions are not supported for this platform.',
    );
  }

  /// @nodoc
  static const FirebaseOptions web = FirebaseOptions(
    apiKey: 'YOUR-WEB-API-KEY',
    appId: 'YOUR-WEB-APP-ID',
    messagingSenderId: 'YOUR-MESSAGING-SENDER-ID (same for all)',
    projectId: 'YOUR-PROJECT-ID (same for all)',
    authDomain: 'YOUR-AUTH-DOMAIN',
    databaseURL: 'YOUR-DATABASE-URL (same for all)',
    storageBucket: 'YOUR-STORAGE-BUCKET (same for all)',
    measurementId: 'YOUR-MEASUREMENT-ID',
  );

  /// @nodoc
  static const FirebaseOptions android = FirebaseOptions(
    apiKey: 'YOUR-ANDROID-API-KEY',
    appId: 'YOUR-ANDROID-APP-ID',
    messagingSenderId: 'YOUR-MESSAGING-SENDER-ID (same for all)',
    projectId: 'YOUR-PROJECT-ID (same for all)',
    databaseURL: 'YOUR-DATABASE-URL (same for all)',
    storageBucket: 'YOUR-STORAGE-BUCKET (same for all)',
  );

  /// @nodoc
  static const FirebaseOptions ios = FirebaseOptions(
    apiKey: 'YOUR-IOS-API-KEY',
    appId: 'YOUR-IOS-APP-ID',
    messagingSenderId: 'YOUR-MESSAGING-SENDER-ID (same for all)',
    projectId: 'YOUR-PROJECT-ID (same for all)',
    databaseURL: 'YOUR-DATABASE-URL (same for all)',
    storageBucket: 'YOUR-STORAGE-BUCKET (same for all)',
    androidClientId: 'YOUR-ANDROID-CLIENT-ID',
    iosClientId: 'YOUR-IOS-CLIENT-ID',
    iosBundleId: 'YOUR-IOS-BUNDLE-ID',
  );
}

Finally, in your Firebase project:

  • enable email/password, Google and anonymous authentication
  • copy firestore.rules content or create your own rules

For web

Create file web/index.html and then copy the following code:

index.html
<!DOCTYPE html>
<html>

<head>
  <!--
    If you are serving your web app in a path other than the root, change the
    href value below to reflect the base path you are serving from.

    The path provided below has to start and end with a slash "/" in order for
    it to work correctly.

    For more details:
    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
  -->
  <base href="/">

  <meta charset="UTF-8">
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
  <meta name="description" content="A new Flutter project.">

  <meta name="google-signin-client_id" content="YOUR GOOGLE CLIENT ID">

  <!-- iOS meta tags & icons -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="wine">
  <link rel="apple-touch-icon" href="icons/Icon-192.png">

  <title>wine</title>
  <link rel="manifest" href="manifest.json">
</head>

<body>
  <!-- This script installs service_worker.js to provide PWA functionality to
       application. For more information, see:
       https://developers.google.com/web/fundamentals/primers/service-workers -->
  <script>
    var serviceWorkerVersion = null;
    var scriptLoaded = false;
    function loadMainDartJs() {
      if (scriptLoaded) {
        return;
      }
      scriptLoaded = true;
      var scriptTag = document.createElement('script');
      scriptTag.src = 'main.dart.js';
      scriptTag.type = 'application/javascript';
      document.body.append(scriptTag);
    }

    if ('serviceWorker' in navigator) {
      // Service workers are supported. Use them.
      window.addEventListener('load', function () {
        // Wait for registration to finish before dropping the <script> tag.
        // Otherwise, the browser will load the script multiple times,
        // potentially different versions.
        var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
        navigator.serviceWorker.register(serviceWorkerUrl)
          .then((reg) => {
            function waitForActivation(serviceWorker) {
              serviceWorker.addEventListener('statechange', () => {
                if (serviceWorker.state == 'activated') {
                  console.log('Installed new service worker.');
                  loadMainDartJs();
                }
              });
            }
            if (!reg.active && (reg.installing || reg.waiting)) {
              // No active web worker and we have installed or are installing
              // one for the first time. Simply wait for it to activate.
              waitForActivation(reg.installing ?? reg.waiting);
            } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
              // When the app updates the serviceWorkerVersion changes, so we
              // need to ask the service worker to update.
              console.log('New service worker available.');
              reg.update();
              waitForActivation(reg.installing);
            } else {
              // Existing service worker is still good.
              console.log('Loading app from service worker.');
              loadMainDartJs();
            }
          });

        // If service worker doesn't succeed in a reasonable amount of time,
        // fallback to plaint <script> tag.
        setTimeout(() => {
          if (!scriptLoaded) {
            console.warn(
              'Failed to load app from service worker. Falling back to plain <script> tag.',
            );
            loadMainDartJs();
          }
        }, 4000);
      });
    } else {
      // Service workers not supported. Just drop the <script> tag.
      loadMainDartJs();
    }
  </script>
</body>

</html>

Unstable, Isar web is still beta.

VSCode launch config

If you'd like to launch WINE from VSCode, copy the config below into .vscode/launch.json.

launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Flutter Dev",
      "request": "launch",
      "type": "dart",
      "program": "lib/main_development.dart",
      "args": ["--flavor", "development"]
    },
    {
      "name": "Flutter Dev Device Preview",
      "request": "launch",
      "type": "dart",
      "program": "lib/main_development_device_preview.dart",
      "args": ["--flavor", "development"]
    },
    {
      "name": "Flutter Dev Web",
      "request": "launch",
      "type": "dart",
      "program": "lib/main_development.dart",
      "args": [
        "--flavor",
        "development",
        "--web-hostname",
        "localhost",
        "--web-port",
        "7357"
      ]
    },
    {
      "name": "Flutter Pro",
      "request": "launch",
      "type": "dart",
      "program": "lib/main_production.dart",
      "args": ["--flavor", "production"]
    }
  ]
}

Misc

WINE wording Common wording
branch chapter/story
tree series