Initial commit: Tagesbyte prototype

Flutter app that collects daily tech news from German and English RSS/Atom
feeds, with a reader view, AI article summaries and daily briefings (Claude
API or n8n webhook), paywall/sponsored filtering and ad/consent blocking.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
CedricandClaude Opus 5.5 committed 2026-10-16 14:53:37 +02:00
commit f12fb1dabb
159 files changed
+8738

No files matched your search

+65
View File
@@ -0,0 +1,65 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
# Windows
Thumbs.db
desktop.ini
# Machine-specific editor settings (absolute paths)
.vscode/settings.json
# Test coverage
coverage/
# Secrets and signing
.env
.env.*
*.keystore
*.jks
key.properties
# Flutter version manager
.fvm/
+39
View File
@@ -0,0 +1,39 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "edada7c56edf4a183c1735310e123c7f923584f1"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
- platform: android
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
- platform: ios
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
- platform: web
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
- platform: windows
create_revision: edada7c56edf4a183c1735310e123c7f923584f1
base_revision: edada7c56edf4a183c1735310e123c7f923584f1
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
+13
View File
@@ -0,0 +1,13 @@
## Agent skills
### Issue tracker
Issues live in Gitea at tea.zendric.de (Cedric/TagesByte), managed with the `tea` CLI. See `docs/agents/issue-tracker.md`.
### Triage labels
Default vocabulary: needs-triage, needs-info, ready-for-agent, ready-for-human, wontfix. See `docs/agents/triage-labels.md`.
### Domain docs
Single-context: one `GLOSSARY.md` and `docs/adr/` at the repo root. See `docs/agents/domain.md`.
+197
View File
@@ -0,0 +1,197 @@
# Tagesbyte
Your daily tech news in bytes. A Flutter app that collects the day's tech news
from German and English RSS/Atom feeds and uses AI to summarize single articles
or write a daily briefing. It's meant to replace the n8n → Discord workflow.
## Features (prototype)
- **Today**: all articles from the enabled sources in the last 12/24/48 h, newest
first. Filter by language or source, pull to refresh.
- **Reading in the app**: tapping an article opens a clean **reader view** (text,
headings, lists, quotes, images) without ads or cookie banners. The globe icon
switches to the **original page** in an in-app WebView, for paywalls or sites
that block reader view. **Summarize with AI** uses the same downloaded text, so
the summary is based on the full article, not just the RSS teaser. Links in the
briefing open the same way.
- **Briefing**: AI picks the 6–10 most important stories of the day, merges
coverage from different outlets, and links every topic to its sources. Every
briefing is saved on the device (`briefings.json` in the app's private
storage); the history button lists them by month, tap to read, swipe to delete
(with undo).
- **Paid articles and ads hidden**: heise+ and Golem `(g+)` are recognized by
their title; SPIEGEL+ and t3n Pro by a marker in the article page, which the app
checks once per new article in the background (it reads only until the marker,
and remembers results for 14 days). Sponsored posts (`Anzeige:`) are hidden too.
The feed header shows how many were hidden; both filters can be turned off.
- **Ad and cookie-banner blocking** in the original-page view: requests to ~80
ad/tracker hosts and the common consent managers (Sourcepoint, OneTrust,
consentmanager, Usercentrics, Didomi, Cookiebot, …) are blocked, and a
stylesheet hides leftover ad slots and banners. Nothing is accepted, so sites
treat it like a rejection. Golem redirects to a separate consent page instead
of showing a banner; with "Accept cookie walls" on (default), the app makes the
same request as Golem's own "Zustimmen" button (`/abo/setconsentcookie.php`,
valid for a day) and reuses the cookie for reader view and the in-app page.
With it off, the app shows the teaser and an "Open website anyway" option.
- **Sources**: 21 curated feeds (12 German, 9 English), toggle each one, or add any
RSS/Atom feed (it's validated before being added).
- **Dark mode**: System / Light / Dark in Settings (applies instantly). The
original-page view follows it too: when the phone is dark, sites use their own
dark design or Android darkens them; when only the app is dark, the app inverts
the page colours and keeps photos and videos as they are.
- **Settings**: AI provider (off / Claude API / n8n webhook), model, summary
language (German/English, whatever the source language), time window, paid/ad
filters, ad and cookie-banner blocking.
## Running
```bash
flutter pub get
flutter run # pick an Android emulator/device
flutter test # unit tests (parser, Claude request/response handling)
LIVE_FEEDS=1 flutter test test/live_feeds_test.dart # checks every real feed
```
Platform notes:
- **Android / iOS**: work as-is (Android 6.0+).
- **Windows desktop**: requires Visual Studio with the "Desktop development with
C++" workload. Reader view works; "original page" opens the browser because
the WebView plugin has no Windows support.
- **Web**: browsers block cross-origin feed requests (CORS). Set a CORS proxy
prefix in Settings (only shown on web), or use the app on mobile/desktop.
## AI setup
### Option A: Claude API (direct)
1. Create a key at <https://console.anthropic.com/settings/keys>.
2. Settings → AI summaries → **Claude API** → paste the key → Save.
The key is stored in the platform keystore (`flutter_secure_storage`) and only
sent to `api.anthropic.com`. Model choices:
| Model | Use it for |
|---|---|
| `claude-opus-5-5` (default) | Best briefing quality |
| `claude-sonnet-5-5` | Balanced cost and quality |
| `claude-haiku-5-5` | Cheapest; good enough for single-article summaries |
Requests use low effort (summarizing is routine work) and, for the briefing,
structured JSON output so the result maps reliably to topics and links. On Opus
and Sonnet the app also enables Anthropic's server-side refusal fallback
(`fallbacks: "default"`): if a safety classifier declines a request, the API
retries it on a fallback model.
> Shipping the app to other people with your key inside isn't safe. For
> personal use a key you entered yourself is fine; for distribution, route
> requests through your own backend (e.g. the n8n option below).
### Option B: Your n8n workflow
Settings → AI summaries → **n8n webhook** → enter the production URL of a
*Webhook* trigger node (method POST, "Respond: Using 'Respond to Webhook' node").
The app sends JSON and expects JSON back.
**Daily briefing**
```jsonc
// Request
{
"action": "daily_briefing",
"language": "de", // "de" | "en"
"articles": [
{
"id": "a1",
"title": "…",
"url": "https://…",
"source": "heise online",
"language": "de",
"published": "2026-10-11T07:30:00.000Z",
"excerpt": "…"
}
]
}
// Response, option 1 (structured; topics link back to the articles)
{
"intro": "One or two sentences on the day.",
"topics": [
{ "title": "…", "summary": "…", "article_ids": ["a1", "a7"] }
]
}
// Response, option 2 (plain text, e.g. your existing Discord message)
{ "text": "…" }
```
**Single article**
```jsonc
// Request
{
"action": "summarize_article",
"language": "de",
"article": { "title": "…", "url": "…", "source": "…", "published": "…", "text": "extracted article body" }
}
// Response
{ "summary": "…" } // a plain-text body also works
```
Use a *Switch* node on `{{$json.body.action}}` to route the two cases to your
existing AI nodes.
## News sources
Every feed URL below was checked to load and parse. The ★ sources are enabled by
default.
| | Source | Feed | Focus |
|---|---|---|---|
| 🇩🇪 ★ | heise online | `heise.de/rss/heise-atom.xml` | Broad IT news, high volume (~150/day) |
| 🇩🇪 ★ | Golem.de | `rss.golem.de/rss.php?feed=ATOM1.0` | IT news for professionals |
| 🇩🇪 ★ | t3n | `t3n.de/rss.xml` | Digital business, startups, AI |
| 🇩🇪 ★ | ComputerBase | `computerbase.de/rss/news.xml` | Hardware, software, gaming |
| 🇩🇪 | SPIEGEL Netzwelt | `spiegel.de/netzwelt/index.rss` | Mainstream news magazine view |
| 🇩🇪 | ZEIT Digital | `newsfeed.zeit.de/digital/index` | Digital policy and society |
| 🇩🇪 | netzpolitik.org | `netzpolitik.org/feed/` | Digital rights, privacy |
| 🇩🇪 | heise Security | `heise.de/security/rss/news-atom.xml` | Security vulnerabilities |
| 🇩🇪 | heise Developer | `heise.de/developer/rss/news-atom.xml` | Software development |
| 🇩🇪 | Caschys Blog | `stadt-bremerhaven.de/feed/` | Consumer tech, smartphones |
| 🇩🇪 | derStandard Web | `derstandard.at/rss/web` | Austrian daily's tech section |
| 🇩🇪 | Borns IT- und Windows-Blog | `borncity.com/blog/feed/` | Windows, patches, admin topics |
| 🇬🇧 ★ | The Verge | `theverge.com/rss/index.xml` | Consumer tech, policy |
| 🇬🇧 ★ | Ars Technica | `feeds.arstechnica.com/arstechnica/index` | In-depth tech and science |
| 🇬🇧 ★ | TechCrunch | `techcrunch.com/feed/` | Startups, funding |
| 🇬🇧 ★ | Hacker News | `news.ycombinator.com/rss` | Front page links |
| 🇬🇧 | MIT Technology Review | `technologyreview.com/feed/` | AI, biotech, climate |
| 🇬🇧 | WIRED | `wired.com/feed/rss` | Tech and culture |
| 🇬🇧 | Engadget | `engadget.com/rss.xml` | Gadgets |
| 🇬🇧 | The Register | `theregister.com/headlines.atom` | Enterprise IT |
| 🇬🇧 | BleepingComputer | `bleepingcomputer.com/feed/` | Security, malware |
Reader view works for 20 of the 21 sources. ZEIT Digital blocks non-browser
requests, so the app shows the teaser and offers the original page.
## Project layout
```
lib/
main.dart App entry, theme
data/default_sources.dart Curated feed list
models/ Article, NewsSource, DailyBriefing, AppSettings
services/
feed_parser.dart RSS 2.0 / RSS 1.0 / Atom parser, date parsing
feed_service.dart Parallel fetching, dedupe, time window
article_extractor.dart Article page → reader blocks + text for the AI
summarizer.dart Summarizer interface and shared prompt input
claude_summarizer.dart Claude Messages API over HTTP
n8n_summarizer.dart n8n webhook bridge
storage.dart Settings, sources, briefing persistence
paywall_service.dart Paid/sponsored detection (titles + page marker)
content_blocking.dart Ad/tracker/consent blocklists for the WebView
consent_service.dart Accepts consent walls (Golem) and keeps the cookies
state/app_state.dart ChangeNotifier holding app state
ui/ Screens (Today, Article, Briefing, Sources, Settings)
```
+28
View File
@@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
+14
View File
@@ -0,0 +1,14 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
.cxx/
# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks
+44
View File
@@ -0,0 +1,44 @@
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
}
android {
namespace = "de.dailytechnews.daily_tech_news"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "de.dailytechnews.daily_tech_news"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = 23 // flutter_secure_storage needs Android 6.0+
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
}
}
}
flutter {
source = "../.."
}
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
+53
View File
@@ -0,0 +1,53 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="Tagesbyte"
android:name="${applicationName}"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<!-- url_launcher: open article links in the browser -->
<intent>
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="https"/>
</intent>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>
@@ -0,0 +1,5 @@
package de.dailytechnews.daily_tech_news
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity()
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground>
<inset
android:drawable="@drawable/ic_launcher_foreground"
android:inset="0%" />
</foreground>
<monochrome>
<inset
android:drawable="@drawable/ic_launcher_monochrome"
android:inset="0%" />
</monochrome>
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
+21
View File
@@ -0,0 +1,21 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}
+3
View File
@@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
+5
View File
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
+25
View File
@@ -0,0 +1,25 @@
pluginManagement {
val flutterSdkPath = run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
flutterSdkPath
}
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.3" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
}
include(":app")
Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

+8
View File
@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" width="1000" height="1000">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5873FF"/>
<stop offset="1" stop-color="#2231A6"/>
</linearGradient>
</defs>
<rect width="1000" height="1000" fill="url(#bg)"/></svg>

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

+25
View File
@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" width="1000" height="1000">
<defs>
<mask id="bite" maskUnits="userSpaceOnUse" x="0" y="0" width="1000" height="1000">
<rect width="1000" height="1000" fill="#fff"/>
<circle cx="692.0188835160362" cy="274.5048250192058" r="88" fill="#000"/><circle cx="665.4951749807942" cy="247.98111648396377" r="88" fill="#000"/>
</mask>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="16"/>
</filter>
</defs>
<g transform="translate(500 500) scale(0.9) translate(-500 -500)">
<!-- Blur after cutting the bite so the shadow follows the bitten edge. -->
<g transform="translate(0 24)" filter="url(#shadow)" opacity="0.35">
<g mask="url(#bite)"><rect x="290" y="230" width="420" height="540" rx="52" fill="#0B1460" /></g>
</g>
<g mask="url(#bite)"><rect x="290" y="230" width="420" height="540" rx="52" fill="#FFFFFF" /></g>
<rect x="345" y="335" width="215" height="50" rx="25" fill="#3355DD"/>
<rect x="345" y="420" width="155" height="50" rx="25" fill="#3355DD"/>
<rect x="345" y="525" width="310" height="28" rx="14" fill="#C9D3F7"/>
<rect x="345" y="588" width="310" height="28" rx="14" fill="#C9D3F7"/>
<rect x="345" y="651" width="200" height="28" rx="14" fill="#C9D3F7"/>
<path d="M615,619 C620.52,659.48 620.52,659.48 661,665 C620.52,670.52 620.52,670.52 615,711 C609.48,670.52 609.48,670.52 569,665 C609.48,659.48 609.48,659.48 615,619 Z" fill="#FFB52E"/>
</g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

+32
View File
@@ -0,0 +1,32 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" width="1000" height="1000">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5873FF"/>
<stop offset="1" stop-color="#2231A6"/>
</linearGradient>
</defs>
<rect width="1000" height="1000" fill="url(#bg)"/>
<defs>
<mask id="bite" maskUnits="userSpaceOnUse" x="0" y="0" width="1000" height="1000">
<rect width="1000" height="1000" fill="#fff"/>
<circle cx="692.0188835160362" cy="274.5048250192058" r="88" fill="#000"/><circle cx="665.4951749807942" cy="247.98111648396377" r="88" fill="#000"/>
</mask>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="16"/>
</filter>
</defs>
<g transform="translate(500 500) scale(1.1) translate(-500 -500)">
<!-- Blur after cutting the bite so the shadow follows the bitten edge. -->
<g transform="translate(0 24)" filter="url(#shadow)" opacity="0.35">
<g mask="url(#bite)"><rect x="290" y="230" width="420" height="540" rx="52" fill="#0B1460" /></g>
</g>
<g mask="url(#bite)"><rect x="290" y="230" width="420" height="540" rx="52" fill="#FFFFFF" /></g>
<rect x="345" y="335" width="215" height="50" rx="25" fill="#3355DD"/>
<rect x="345" y="420" width="155" height="50" rx="25" fill="#3355DD"/>
<rect x="345" y="525" width="310" height="28" rx="14" fill="#C9D3F7"/>
<rect x="345" y="588" width="310" height="28" rx="14" fill="#C9D3F7"/>
<rect x="345" y="651" width="200" height="28" rx="14" fill="#C9D3F7"/>
<path d="M615,619 C620.52,659.48 620.52,659.48 661,665 C620.52,670.52 620.52,670.52 615,711 C609.48,670.52 609.48,670.52 569,665 C609.48,659.48 609.48,659.48 615,619 Z" fill="#FFB52E"/>
</g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+123
View File
@@ -0,0 +1,123 @@
// Generates the Tagesbyte app icon sources (SVG) and PNG renders.
// Usage: npm install @resvg/resvg-js@2.6.2 && node make_icons.js assets/icon
// then: dart run flutter_launcher_icons
const fs = require('fs');
const path = require('path');
const { Resvg } = require('@resvg/resvg-js');
const out = process.argv[2];
fs.mkdirSync(out, { recursive: true });
const BLUE = '#3355DD';
const LINE = '#C9D3F7';
const SPARK = '#FFB52E';
// Design space 1000x1000. A news page with a bite out of its top-right corner.
const page = { x: 290, y: 230, w: 420, h: 540, r: 52 };
const corner = { x: page.x + page.w, y: page.y };
// Two overlapping circles: together they remove the corner and leave a small
// cusp between them, which reads as a bite mark.
const biteCircles = [112, 158].map((deg) => {
const a = (deg * Math.PI) / 180;
return { cx: corner.x + 48 * Math.cos(a), cy: corner.y + 48 * Math.sin(a), r: 88 };
});
const sparkle = (cx, cy, s) =>
`M${cx},${cy - s} C${cx + s * 0.12},${cy - s * 0.12} ${cx + s * 0.12},${cy - s * 0.12} ${cx + s},${cy} ` +
`C${cx + s * 0.12},${cy + s * 0.12} ${cx + s * 0.12},${cy + s * 0.12} ${cx},${cy + s} ` +
`C${cx - s * 0.12},${cy + s * 0.12} ${cx - s * 0.12},${cy + s * 0.12} ${cx - s},${cy} ` +
`C${cx - s * 0.12},${cy - s * 0.12} ${cx - s * 0.12},${cy - s * 0.12} ${cx},${cy - s} Z`;
const pageRect = (fill, extra = '') =>
`<rect x="${page.x}" y="${page.y}" width="${page.w}" height="${page.h}" rx="${page.r}" fill="${fill}" ${extra}/>`;
const biteMask = (id) => `
<mask id="${id}" maskUnits="userSpaceOnUse" x="0" y="0" width="1000" height="1000">
<rect width="1000" height="1000" fill="#fff"/>
${biteCircles.map((c) => `<circle cx="${c.cx}" cy="${c.cy}" r="${c.r}" fill="#000"/>`).join('')}
</mask>`;
// Headline bar, text lines and the AI sparkle on the page.
const contentShapes = (headline, line, spark) => `
<rect x="345" y="335" width="215" height="50" rx="25" fill="${headline}"/>
<rect x="345" y="420" width="155" height="50" rx="25" fill="${headline}"/>
<rect x="345" y="525" width="310" height="28" rx="14" fill="${line}"/>
<rect x="345" y="588" width="310" height="28" rx="14" fill="${line}"/>
<rect x="345" y="651" width="200" height="28" rx="14" fill="${line}"/>
<path d="${sparkle(615, 665, 46)}" fill="${spark}"/>`;
function foreground(scale) {
const t = `translate(500 500) scale(${scale}) translate(-500 -500)`;
return `
<defs>
${biteMask('bite')}
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="16"/>
</filter>
</defs>
<g transform="${t}">
<!-- Blur after cutting the bite so the shadow follows the bitten edge. -->
<g transform="translate(0 24)" filter="url(#shadow)" opacity="0.35">
<g mask="url(#bite)">${pageRect('#0B1460')}</g>
</g>
<g mask="url(#bite)">${pageRect('#FFFFFF')}</g>
${contentShapes(BLUE, LINE, SPARK)}
</g>`;
}
const background = `
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5873FF"/>
<stop offset="1" stop-color="#2231A6"/>
</linearGradient>
</defs>
<rect width="1000" height="1000" fill="url(#bg)"/>`;
const svg = (body) =>
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" width="1000" height="1000">${body}</svg>`;
// Monochrome (Android 13 themed icons): page silhouette, content cut out.
const monochrome = svg(`
<defs>
${biteMask('bite')}
<mask id="content" maskUnits="userSpaceOnUse" x="0" y="0" width="1000" height="1000">
<rect width="1000" height="1000" fill="#fff"/>
${contentShapes('#000', '#000', '#000')}
</mask>
</defs>
<g transform="translate(500 500) scale(0.9) translate(-500 -500)">
<g mask="url(#bite)"><g mask="url(#content)">${pageRect('#FFFFFF')}</g></g>
</g>`);
const files = {
// Full-bleed icon for iOS, web and Windows (the OS rounds the corners).
'icon.svg': svg(background + foreground(1.1)),
// Android adaptive icon layers: content kept inside the 66dp safe zone.
'foreground.svg': svg(foreground(0.9)),
'background.svg': svg(background),
'monochrome.svg': monochrome,
};
for (const [name, content] of Object.entries(files)) {
fs.writeFileSync(path.join(out, name), content);
const png = new Resvg(content, { fitTo: { mode: 'width', value: 1024 } }).render().asPng();
fs.writeFileSync(path.join(out, name.replace('.svg', '.png')), png);
console.log('wrote', name, 'and', name.replace('.svg', '.png'));
}
// Preview: the full icon at launcher size plus a circle-masked adaptive icon.
const preview = svg(`
<defs><clipPath id="c"><circle cx="500" cy="500" r="500"/></clipPath></defs>
<g clip-path="url(#c)">${background}${foreground(0.9)}</g>`);
fs.writeFileSync(path.join(out, '_preview_adaptive.png'),
new Resvg(preview, { fitTo: { mode: 'width', value: 512 } }).render().asPng());
// Monochrome preview on a dark background (the real file is transparent), and
// the full icon at a real launcher size to check it still reads when small.
const inner = (s) => s.replace(/^<svg[^>]*>/, '').replace(/<\/svg>$/, '');
fs.writeFileSync(path.join(out, '_preview_monochrome.png'),
new Resvg(svg('<rect width="1000" height="1000" fill="#333"/>' + inner(monochrome)),
{ fitTo: { mode: 'width', value: 256 } }).render().asPng());
fs.writeFileSync(path.join(out, '_preview_small.png'),
new Resvg(files['icon.svg'], { fitTo: { mode: 'width', value: 96 } }).render().asPng());
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+21
View File
@@ -0,0 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" width="1000" height="1000">
<defs>
<mask id="bite" maskUnits="userSpaceOnUse" x="0" y="0" width="1000" height="1000">
<rect width="1000" height="1000" fill="#fff"/>
<circle cx="692.0188835160362" cy="274.5048250192058" r="88" fill="#000"/><circle cx="665.4951749807942" cy="247.98111648396377" r="88" fill="#000"/>
</mask>
<mask id="content" maskUnits="userSpaceOnUse" x="0" y="0" width="1000" height="1000">
<rect width="1000" height="1000" fill="#fff"/>
<rect x="345" y="335" width="215" height="50" rx="25" fill="#000"/>
<rect x="345" y="420" width="155" height="50" rx="25" fill="#000"/>
<rect x="345" y="525" width="310" height="28" rx="14" fill="#000"/>
<rect x="345" y="588" width="310" height="28" rx="14" fill="#000"/>
<rect x="345" y="651" width="200" height="28" rx="14" fill="#000"/>
<path d="M615,619 C620.52,659.48 620.52,659.48 661,665 C620.52,670.52 620.52,670.52 615,711 C609.48,670.52 609.48,670.52 569,665 C609.48,659.48 609.48,659.48 615,619 Z" fill="#000"/>
</mask>
</defs>
<g transform="translate(500 500) scale(0.9) translate(-500 -500)">
<g mask="url(#bite)"><g mask="url(#content)"><rect x="290" y="230" width="420" height="540" rx="52" fill="#FFFFFF" /></g></g>
</g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+51
View File
@@ -0,0 +1,51 @@
# Domain Docs
How the engineering skills should consume this repo's domain documentation when exploring the codebase.
## Before exploring, read these
- **`GLOSSARY.md`** at the repo root, or
- **`GLOSSARY-MAP.md`** at the repo root if it exists: it points at one `GLOSSARY.md` per context. Read each one relevant to the topic.
- **`docs/adr/`**: read ADRs that touch the area you're about to work in. In multi-context repos, also check `src/<context>/docs/adr/` for context-scoped decisions.
If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/domain-modeling` skill (reached via `/grill-with-docs` and `/improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved.
## File structure
Single-context repo (most repos):
```
/
├── GLOSSARY.md
├── docs/adr/
│ ├── 0001-event-sourced-orders.md
│ └── 0002-postgres-for-write-model.md
└── src/
```
Multi-context repo (presence of `GLOSSARY-MAP.md` at the root):
```
/
├── GLOSSARY-MAP.md
├── docs/adr/ ← system-wide decisions
└── src/
├── ordering/
│ ├── GLOSSARY.md
│ └── docs/adr/ ← context-specific decisions
└── billing/
├── GLOSSARY.md
└── docs/adr/
```
## Use the glossary's vocabulary
When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `GLOSSARY.md`. Don't drift to synonyms the glossary explicitly avoids.
If the concept you need isn't in the glossary yet, that's a signal: either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/domain-modeling`).
## Flag ADR conflicts
If your output contradicts an existing ADR, surface it explicitly rather than silently overriding:
> _Contradicts ADR-0007 (event-sourced orders), but worth reopening because…_
+40
View File
@@ -0,0 +1,40 @@
# Issue tracker: Gitea
Issues and specs for this repo live as issues on the self-hosted Gitea instance at https://tea.zendric.de, repo `Cedric/TagesByte`. Use the `tea` CLI for all operations.
`tea` infers the repo from the `origin` remote (`ssh://git@tea.zendric.de:2223/Cedric/TagesByte.git`). If inference fails, add `--repo Cedric/TagesByte`.
## Conventions
- **Create an issue**: `tea issues create --title "..." --description "..."`. For multi-line bodies, pipe a heredoc into `--description-file -`.
- **Read an issue**: `tea api repos/{owner}/{repo}/issues/<n>` for the issue as JSON, and `tea api repos/{owner}/{repo}/issues/<n>/comments` for its comments.
- **List issues**: `tea issues list --state open --fields index,title,body,labels -o json`, with `--labels "..."` / `--state` filters as needed.
- **Make an issue a child of a parent**: Gitea has no sub-issues. Put `Part of #<parent>` at the top of the child body, and add `- [ ] #<child>` to a task list in the parent body.
- **Comment on an issue**: `tea comment <n> "..."`
- **Apply / remove labels**: `tea issues edit <n> --add-labels "..."` / `--remove-labels "..."`
- **Close**: `tea comment <n> "..."`, then `tea issues close <n>`.
## Pull requests as a triage surface
**PRs as a request surface: no.** _(Set to `yes` if this repo treats external PRs as feature requests; `/triage` reads this flag.)_
When set to `yes`, PRs run through the same labels and states as issues, using `tea pulls` (`tea pulls list`, `tea pulls <n>`) and `tea api repos/{owner}/{repo}/pulls/<n>.diff` for the diff. Gitea shares one number space across issues and PRs.
## When a skill says "publish to the issue tracker"
Create a Gitea issue.
## When a skill says "fetch the relevant ticket"
Read it as in **Read an issue** above.
## Wayfinding operations
Used by `/wayfinder`. The **map** is a single issue with **child** issues as tickets.
- **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `tea issues create --labels wayfinder:map ...`.
- **Child ticket**: linked to the map as in **Make an issue a child of a parent**. Labels: `wayfinder:<type>` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev.
- **Blocking**: Gitea's native issue dependencies. Add an edge with `tea api -X POST repos/{owner}/{repo}/issues/<child>/dependencies -F index=<blocker> -f owner=Cedric -f repo=TagesByte`. List a ticket's blockers with `tea api repos/{owner}/{repo}/issues/<child>/dependencies`. A ticket is unblocked when every blocker is closed.
- **Frontier query**: list the map's open children (from its task list), drop any with an open blocker or an assignee; first in map order wins.
- **Claim**: `tea issues edit <n> --add-assignees Cedric`, the session's first write.
- **Resolve**: `tea comment <n> "<answer>"`, then `tea issues close <n>`, then append a context pointer (gist + link) to the map's Decisions-so-far.
+15
View File
@@ -0,0 +1,15 @@
# Triage Labels
The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker.
| Label in mattpocock/skills | Label in our tracker | Meaning |
| -------------------------- | -------------------- | ---------------------------------------- |
| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue |
| `needs-info` | `needs-info` | Waiting on reporter for more information |
| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent |
| `ready-for-human` | `ready-for-human` | Requires human implementation |
| `wontfix` | `wontfix` | Will not be actioned |
When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table.
Edit the "Label in our tracker" column to match whatever vocabulary you actually use.
+13
View File
@@ -0,0 +1,13 @@
Hey i want to have an app that gives me daily tech news.
Please ask me questions if something is unclear/could be improved
The app should be build using flutter.
I currently already have a n8n workflow to get daily tech news, and it send me them via discord.
I want to replace this.
For this we need to get data from tech newspapers etc. Please provide me a list of sources. (language preferably german/english could be fine aswell)
It would be amazing if i could integrate some ai to summarize the articles.
This is what my n8n does already currently( maybe we can depend on this workflow for the app).
Can you develop me an inital prototype
+34
View File
@@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>
+1
View File
@@ -0,0 +1 @@
#include "Generated.xcconfig"
+1
View File
@@ -0,0 +1 @@
#include "Generated.xcconfig"
+616
View File
@@ -0,0 +1,616 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = de.dailytechnews.dailyTechNews;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = de.dailytechnews.dailyTechNews.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = de.dailytechnews.dailyTechNews.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = de.dailytechnews.dailyTechNews.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = de.dailytechnews.dailyTechNews;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = de.dailytechnews.dailyTechNews;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
+13
View File
@@ -0,0 +1,13 @@
import Flutter
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
@@ -0,0 +1 @@
{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 732 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

@@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
+47
View File
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Tagesbyte</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Tagesbyte</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<!-- Portrait-only on iPad requires opting out of multitasking. -->
<key>UIRequiresFullScreen</key>
<true/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>
+1
View File
@@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"
+12
View File
@@ -0,0 +1,12 @@
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}
+187
View File
@@ -0,0 +1,187 @@
import '../models/news_source.dart';
/// Curated tech news feeds. All URLs were checked to return a valid RSS/Atom
/// feed. Users can toggle them and add their own in the Sources tab.
const defaultSources = <NewsSource>[
// --- German -------------------------------------------------------------
NewsSource(
id: 'heise',
name: 'heise online',
feedUrl: 'https://www.heise.de/rss/heise-atom.xml',
homepage: 'https://www.heise.de',
language: SourceLanguage.de,
description: 'IT-Nachrichten, breit aufgestellt (hohes Volumen)',
enabledByDefault: true,
),
NewsSource(
id: 'golem',
name: 'Golem.de',
feedUrl: 'https://rss.golem.de/rss.php?feed=ATOM1.0',
homepage: 'https://www.golem.de',
language: SourceLanguage.de,
description: 'IT-News für Profis',
enabledByDefault: true,
),
NewsSource(
id: 't3n',
name: 't3n',
feedUrl: 'https://t3n.de/rss.xml',
homepage: 'https://t3n.de',
language: SourceLanguage.de,
description: 'Digitales Business, Startups, KI',
enabledByDefault: true,
checkPaywallOnPage: true,
),
NewsSource(
id: 'computerbase',
name: 'ComputerBase',
feedUrl: 'https://www.computerbase.de/rss/news.xml',
homepage: 'https://www.computerbase.de',
language: SourceLanguage.de,
description: 'Hardware, Software, Gaming',
enabledByDefault: true,
),
NewsSource(
id: 'spiegel-netzwelt',
name: 'SPIEGEL Netzwelt',
feedUrl: 'https://www.spiegel.de/netzwelt/index.rss',
homepage: 'https://www.spiegel.de/netzwelt/',
language: SourceLanguage.de,
description: 'Digitales aus Sicht eines Nachrichtenmagazins',
checkPaywallOnPage: true,
),
NewsSource(
id: 'zeit-digital',
name: 'ZEIT Digital',
feedUrl: 'https://newsfeed.zeit.de/digital/index',
homepage: 'https://www.zeit.de/digital/',
language: SourceLanguage.de,
description: 'Digitalpolitik und Gesellschaft',
),
NewsSource(
id: 'netzpolitik',
name: 'netzpolitik.org',
feedUrl: 'https://netzpolitik.org/feed/',
homepage: 'https://netzpolitik.org',
language: SourceLanguage.de,
description: 'Digitale Freiheitsrechte, Datenschutz',
),
NewsSource(
id: 'heise-security',
name: 'heise Security',
feedUrl: 'https://www.heise.de/security/rss/news-atom.xml',
homepage: 'https://www.heise.de/security/',
language: SourceLanguage.de,
description: 'Sicherheitslücken und Security-News',
),
NewsSource(
id: 'heise-developer',
name: 'heise Developer',
feedUrl: 'https://www.heise.de/developer/rss/news-atom.xml',
homepage: 'https://www.heise.de/developer/',
language: SourceLanguage.de,
description: 'Softwareentwicklung',
),
NewsSource(
id: 'caschy',
name: "Caschys Blog",
feedUrl: 'https://stadt-bremerhaven.de/feed/',
homepage: 'https://stadt-bremerhaven.de',
language: SourceLanguage.de,
description: 'Consumer-Tech, Smartphones, Streaming',
),
NewsSource(
id: 'derstandard-web',
name: 'derStandard Web',
feedUrl: 'https://www.derstandard.at/rss/web',
homepage: 'https://www.derstandard.at/web',
language: SourceLanguage.de,
description: 'Tech-Ressort der österreichischen Tageszeitung',
),
NewsSource(
id: 'borncity',
name: 'Borns IT- und Windows-Blog',
feedUrl: 'https://www.borncity.com/blog/feed/',
homepage: 'https://www.borncity.com/blog/',
language: SourceLanguage.de,
description: 'Windows, Patches, Admin-Themen',
),
// --- English ------------------------------------------------------------
NewsSource(
id: 'verge',
name: 'The Verge',
feedUrl: 'https://www.theverge.com/rss/index.xml',
homepage: 'https://www.theverge.com',
language: SourceLanguage.en,
description: 'Consumer tech, culture, policy',
enabledByDefault: true,
),
NewsSource(
id: 'arstechnica',
name: 'Ars Technica',
feedUrl: 'https://feeds.arstechnica.com/arstechnica/index',
homepage: 'https://arstechnica.com',
language: SourceLanguage.en,
description: 'In-depth tech and science',
enabledByDefault: true,
),
NewsSource(
id: 'techcrunch',
name: 'TechCrunch',
feedUrl: 'https://techcrunch.com/feed/',
homepage: 'https://techcrunch.com',
language: SourceLanguage.en,
description: 'Startups, funding, big tech',
enabledByDefault: true,
),
NewsSource(
id: 'hackernews',
name: 'Hacker News',
feedUrl: 'https://news.ycombinator.com/rss',
homepage: 'https://news.ycombinator.com',
language: SourceLanguage.en,
description: 'Front page links, ranked by readers',
enabledByDefault: true,
),
NewsSource(
id: 'mit-tr',
name: 'MIT Technology Review',
feedUrl: 'https://www.technologyreview.com/feed/',
homepage: 'https://www.technologyreview.com',
language: SourceLanguage.en,
description: 'AI, biotech, climate tech',
),
NewsSource(
id: 'wired',
name: 'WIRED',
feedUrl: 'https://www.wired.com/feed/rss',
homepage: 'https://www.wired.com',
language: SourceLanguage.en,
description: 'Tech, science and culture',
),
NewsSource(
id: 'engadget',
name: 'Engadget',
feedUrl: 'https://www.engadget.com/rss.xml',
homepage: 'https://www.engadget.com',
language: SourceLanguage.en,
description: 'Gadgets and consumer electronics',
),
NewsSource(
id: 'theregister',
name: 'The Register',
feedUrl: 'https://www.theregister.com/headlines.atom',
homepage: 'https://www.theregister.com',
language: SourceLanguage.en,
description: 'Enterprise IT with attitude',
),
NewsSource(
id: 'bleepingcomputer',
name: 'BleepingComputer',
feedUrl: 'https://www.bleepingcomputer.com/feed/',
homepage: 'https://www.bleepingcomputer.com',
language: SourceLanguage.en,
description: 'Security and malware news',
),
];
+45
View File
@@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'services/storage.dart';
import 'state/app_state.dart';
import 'ui/common.dart';
import 'ui/home_shell.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Portrait only; also set in AndroidManifest.xml and Info.plist.
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
final state = AppState(await Storage.open());
runApp(DailyTechNewsApp(state: state));
state.init();
}
class DailyTechNewsApp extends StatelessWidget {
const DailyTechNewsApp({super.key, required this.state});
final AppState state;
static const _seed = Color(0xFF3355DD);
@override
Widget build(BuildContext context) {
ThemeData theme(Brightness brightness) => ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: _seed, brightness: brightness),
cardTheme: const CardThemeData(margin: EdgeInsets.zero),
);
// Rebuild when the theme setting changes; everything else listens itself.
return ListenableBuilder(
listenable: state,
builder: (context, _) => MaterialApp(
title: appName,
debugShowCheckedModeBanner: false,
theme: theme(Brightness.light),
darkTheme: theme(Brightness.dark),
themeMode: state.settings.themeMode,
home: HomeShell(state: state),
),
);
}
}
Loaded 100 of 159 files, more files were not shown because too many files have changed in this diff. Show more