Skip to content

Commit c8011d0

Browse files
committed
chore: prepare for mobile publishing and update website branding
1 parent c31f7c9 commit c8011d0

23 files changed

Lines changed: 109 additions & 559 deletions

PUBLISHING_GUIDE.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Publishing Guide — Patterns
2+
3+
This guide outlines the final steps and metadata required to publish **Patterns** to the Apple App Store and Google Play Store.
4+
5+
## 1. Store Metadata
6+
7+
### App Information
8+
- **Name:** Patterns
9+
- **Subtitle (iOS):** Clarity for the mind
10+
- **Short Description (Android):** Daily journaling and OCD tracking through structured reflection.
11+
- **Category:** Health & Fitness or Medical (Reflection/Self-Tracking)
12+
- **Primary Language:** English
13+
14+
### Descriptions
15+
**Full Description:**
16+
Patterns is a focused application designed for daily journaling and tracking obsessive-compulsive patterns. It provides a clean, private, and minimal space to record your thoughts, behaviors, and emotional trends.
17+
18+
Key Features:
19+
- Daily Journaling: Minimalist writing space for chronological reflection.
20+
- OCD Tracking: Structure tools to document obsessions, compulsions, and distress levels (0-10).
21+
- Local-First Privacy: All data stays on your device. No cloud, no tracking, no third-party sharing.
22+
- Structured Insights: Visualize your distress trends and consistency over time.
23+
24+
Note: Patterns is for personal reflection and self-tracking. It does not diagnose, treat, or replace care from a qualified clinician.
25+
26+
**Keywords (iOS):**
27+
journal, ocd tracker, mental health, reflection, thought tracker, compulsions, distress, privacy, minimalist
28+
29+
## 2. Privacy Policy
30+
- **URL:** [https://maskedsyntax.com/patterns/privacy](https://maskedsyntax.com/patterns/privacy)
31+
- **Data Collection:** The app does not collect any data. All data is stored locally on the user's device.
32+
- **Data Deletion:** Users can delete individual entries or use the "Wipe all data" button in Settings to clear all local storage.
33+
34+
## 3. Screenshots Checklist
35+
Prepare screenshots for:
36+
- iPhone (6.7" and 6.5")
37+
- iPad (12.9" 6th Gen and 2nd Gen)
38+
- Android Phone (at least 2)
39+
- Android Tablet (7-inch and 10-inch)
40+
41+
**Scenes to capture:**
42+
1. Welcome Screen (Calm onboarding)
43+
2. Home (Today's overview)
44+
3. Journal Editor (Clean writing space)
45+
4. OCD Entry Flow (Structured tracking)
46+
5. Insights Screen (Trend charts)
47+
48+
## 4. Release Signing (Android)
49+
50+
To build a release APK/AAB for Google Play:
51+
1. Create a keystore: `keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload`
52+
2. Create `android/key.properties` (do NOT commit this):
53+
```properties
54+
storePassword=<your-password>
55+
keyPassword=<your-password>
56+
keyAlias=upload
57+
storeFile=<path-to-keystore>
58+
```
59+
3. Update `android/app/build.gradle.kts` to use the signing configuration.
60+
61+
## 5. Final Verification
62+
1. Run `flutter analyze`
63+
2. Run `flutter test`
64+
3. Build artifacts:
65+
- Android: `flutter build appbundle`
66+
- iOS: `flutter build ipa`

ios/Podfile.lock

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,6 @@ PODS:
3434
- DKImagePickerController/PhotoGallery
3535
- Flutter
3636
- Flutter (1.0.0)
37-
- flutter_keyboard_visibility_temp_fork (0.0.1):
38-
- Flutter
39-
- package_info_plus (0.4.5):
40-
- Flutter
41-
- quill_native_bridge_ios (0.0.1):
42-
- Flutter
4337
- SDWebImage (5.21.7):
4438
- SDWebImage/Core (= 5.21.7)
4539
- SDWebImage/Core (5.21.7)
@@ -56,9 +50,6 @@ PODS:
5650
DEPENDENCIES:
5751
- file_picker (from `.symlinks/plugins/file_picker/ios`)
5852
- Flutter (from `Flutter`)
59-
- flutter_keyboard_visibility_temp_fork (from `.symlinks/plugins/flutter_keyboard_visibility_temp_fork/ios`)
60-
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
61-
- quill_native_bridge_ios (from `.symlinks/plugins/quill_native_bridge_ios/ios`)
6253
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
6354
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
6455
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
@@ -75,12 +66,6 @@ EXTERNAL SOURCES:
7566
:path: ".symlinks/plugins/file_picker/ios"
7667
Flutter:
7768
:path: Flutter
78-
flutter_keyboard_visibility_temp_fork:
79-
:path: ".symlinks/plugins/flutter_keyboard_visibility_temp_fork/ios"
80-
package_info_plus:
81-
:path: ".symlinks/plugins/package_info_plus/ios"
82-
quill_native_bridge_ios:
83-
:path: ".symlinks/plugins/quill_native_bridge_ios/ios"
8469
shared_preferences_foundation:
8570
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
8671
sqflite_darwin:
@@ -93,9 +78,6 @@ SPEC CHECKSUMS:
9378
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
9479
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
9580
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
96-
flutter_keyboard_visibility_temp_fork: 95b2d534bacf6ac62e7fcbe5c2a9e2c2a17ce06f
97-
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
98-
quill_native_bridge_ios: f47af4b14e7757968486641656c5d23250cee521
9981
SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf
10082
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
10183
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0

lib/main.dart

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
22
import 'package:flutter_riverpod/flutter_riverpod.dart';
33
import 'package:google_fonts/google_fonts.dart';
44
import 'package:line_icons/line_icons.dart';
5-
import 'package:window_manager/window_manager.dart';
65
import 'mobile/main_shell.dart';
76
import 'mobile/preferences.dart';
87
import 'theme/app_theme.dart';
@@ -43,24 +42,7 @@ void main() async {
4342
WidgetsFlutterBinding.ensureInitialized();
4443
GoogleFonts.config.allowRuntimeFetching = false;
4544

46-
if (kIsDesktop) {
47-
await windowManager.ensureInitialized();
48-
49-
const windowOptions = WindowOptions(
50-
size: Size(1440, 900),
51-
minimumSize: Size(1440, 900),
52-
center: true,
53-
backgroundColor: Colors.transparent,
54-
skipTaskbar: false,
55-
titleBarStyle: TitleBarStyle.hidden,
56-
);
57-
58-
windowManager.waitUntilReadyToShow(windowOptions, () async {
59-
await windowManager.setResizable(false);
60-
await windowManager.show();
61-
await windowManager.focus();
62-
});
63-
} else {
45+
if (!kIsDesktop) {
6446
await initMobilePreferences();
6547
}
6648

@@ -126,10 +108,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
126108
),
127109
child: Column(
128110
children: [
129-
const SizedBox(
130-
height: 48,
131-
child: DragToMoveArea(child: SizedBox.expand()),
132-
),
111+
const SizedBox(height: 56), // Placeholder for drag area
133112
const SizedBox(height: 8),
134113
_NavIcon(
135114
icon: LineIcons.penNib,

lib/mobile/screens/settings_screen.dart

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:file_picker/file_picker.dart';
44
import 'package:flutter/material.dart';
55
import 'package:flutter_riverpod/flutter_riverpod.dart';
66
import 'package:line_icons/line_icons.dart';
7+
import 'package:url_launcher/url_launcher.dart';
78

89
import '../../database/db_helper.dart';
910
import '../../main.dart';
@@ -289,7 +290,10 @@ class SettingsScreen extends ConsumerWidget {
289290
void _showMessage(BuildContext context, String message) {
290291
ScaffoldMessenger.of(context).showSnackBar(
291292
SnackBar(
292-
content: Text(message),
293+
content: Text(
294+
message,
295+
style: const TextStyle(color: AppTheme.textPrimary),
296+
),
293297
behavior: SnackBarBehavior.floating,
294298
backgroundColor: AppTheme.charcoalInput,
295299
),
@@ -322,6 +326,17 @@ class SettingsScreen extends ConsumerWidget {
322326
'Patterns is for personal reflection and self-tracking. It does not diagnose, treat, or replace care from a qualified clinician.',
323327
style: TextStyle(color: AppTheme.textSecondary, height: 1.45),
324328
),
329+
const SizedBox(height: 20),
330+
SizedBox(
331+
width: double.infinity,
332+
child: OutlinedButton(
333+
onPressed: () => launchUrl(
334+
Uri.parse('https://maskedsyntax.com/patterns/privacy'),
335+
mode: LaunchMode.externalApplication,
336+
),
337+
child: const Text('View full Privacy Policy'),
338+
),
339+
),
325340
],
326341
),
327342
),

lib/screens/analytics_screen.dart

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import 'package:google_fonts/google_fonts.dart';
44
import 'package:line_icons/line_icons.dart';
55
import 'package:fl_chart/fl_chart.dart';
66
import 'package:intl/intl.dart';
7-
import 'package:flutter_heatmap_calendar/flutter_heatmap_calendar.dart';
8-
import 'package:window_manager/window_manager.dart';
97
import '../providers/providers.dart';
108
import '../models/models.dart';
119
import '../widgets/window_controls.dart';
@@ -24,8 +22,7 @@ class AnalyticsScreen extends ConsumerWidget {
2422
backgroundColor: theme.scaffoldBackgroundColor,
2523
appBar: PreferredSize(
2624
preferredSize: const Size.fromHeight(48),
27-
child: DragToMoveArea(
28-
child: Container(
25+
child: Container(
2926
decoration: BoxDecoration(
3027
color: isDark ? Colors.black : Colors.white,
3128
border: Border(
@@ -48,7 +45,6 @@ class AnalyticsScreen extends ConsumerWidget {
4845
),
4946
),
5047
),
51-
),
5248
body: journalAsync.when(
5349
data: (journals) {
5450
return ocdAsync.when(
@@ -134,33 +130,6 @@ class AnalyticsScreen extends ConsumerWidget {
134130
),
135131
const SizedBox(height: 24),
136132

137-
_ChartCard(
138-
title: 'Journaling Consistency',
139-
subtitle: 'Activity over the past year',
140-
height: 180,
141-
theme: theme,
142-
child: HeatMap(
143-
datasets: journalHeatMapData,
144-
colorMode: ColorMode.color,
145-
defaultColor: isDark
146-
? Colors.white.withOpacity(0.05)
147-
: Colors.black.withOpacity(0.05),
148-
textColor: theme.colorScheme.onSurface.withOpacity(
149-
0.6,
150-
),
151-
showColorTip: false,
152-
showText: false,
153-
scrollable: true,
154-
size: 16,
155-
startDate: DateTime.now().subtract(
156-
const Duration(days: 365),
157-
),
158-
endDate: DateTime.now(),
159-
colorsets: {
160-
1: theme.colorScheme.primary.withOpacity(0.8),
161-
},
162-
),
163-
),
164133
const SizedBox(height: 24),
165134

166135
if (ocds.isNotEmpty) ...[

lib/screens/journal_screen.dart

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
44
import 'package:google_fonts/google_fonts.dart';
55
import 'package:intl/intl.dart';
66
import 'package:line_icons/line_icons.dart';
7-
import 'package:window_manager/window_manager.dart';
87
import '../providers/providers.dart';
98
import '../models/models.dart';
109
import '../database/db_helper.dart';
@@ -129,8 +128,7 @@ class _JournalScreenState extends ConsumerState<JournalScreen> {
129128
backgroundColor: theme.scaffoldBackgroundColor,
130129
appBar: PreferredSize(
131130
preferredSize: const Size.fromHeight(48),
132-
child: DragToMoveArea(
133-
child: Container(
131+
child: Container(
134132
decoration: BoxDecoration(
135133
color: isDark ? Colors.black : Colors.white,
136134
border: Border(
@@ -268,7 +266,6 @@ class _JournalScreenState extends ConsumerState<JournalScreen> {
268266
),
269267
),
270268
),
271-
),
272269
body: Row(
273270
children: [
274271
AnimatedContainer(

lib/screens/ocd_tracker_screen.dart

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
33
import 'package:google_fonts/google_fonts.dart';
44
import 'package:intl/intl.dart';
55
import 'package:line_icons/line_icons.dart';
6-
import 'package:window_manager/window_manager.dart';
76
import '../models/models.dart';
87
import '../providers/providers.dart';
98
import '../widgets/window_controls.dart';
@@ -30,8 +29,7 @@ class _OcdTrackerScreenState extends ConsumerState<OcdTrackerScreen> {
3029
backgroundColor: theme.scaffoldBackgroundColor,
3130
appBar: PreferredSize(
3231
preferredSize: const Size.fromHeight(48),
33-
child: DragToMoveArea(
34-
child: Container(
32+
child: Container(
3533
decoration: BoxDecoration(
3634
color: isDark ? Colors.black : Colors.white,
3735
border: Border(
@@ -100,7 +98,6 @@ class _OcdTrackerScreenState extends ConsumerState<OcdTrackerScreen> {
10098
),
10199
),
102100
),
103-
),
104101
body: _OcdListView(type: _selectedType, entries: filteredOcdAsync),
105102
floatingActionButton: FloatingActionButton.extended(
106103
backgroundColor: theme.colorScheme.primary,

lib/screens/settings_screen.dart

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
44
import 'package:file_picker/file_picker.dart';
55
import 'package:google_fonts/google_fonts.dart';
66
import 'package:line_icons/line_icons.dart';
7-
import 'package:window_manager/window_manager.dart';
87
import '../database/db_helper.dart';
98
import '../providers/providers.dart';
109
import '../widgets/window_controls.dart';
@@ -130,8 +129,7 @@ class SettingsScreen extends ConsumerWidget {
130129
backgroundColor: theme.scaffoldBackgroundColor,
131130
appBar: PreferredSize(
132131
preferredSize: const Size.fromHeight(48),
133-
child: DragToMoveArea(
134-
child: Container(
132+
child: Container(
135133
decoration: BoxDecoration(
136134
color: isDark ? Colors.black : Colors.white,
137135
border: Border(
@@ -154,7 +152,6 @@ class SettingsScreen extends ConsumerWidget {
154152
),
155153
),
156154
),
157-
),
158155
body: Center(
159156
child: Container(
160157
constraints: const BoxConstraints(maxWidth: 800),

0 commit comments

Comments
 (0)