ruby_everywhere 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +255 -0
- data/bridge/everywhere/bridge.js +60 -3
- data/lib/everywhere/android_resources.rb +217 -0
- data/lib/everywhere/android_sdk.rb +330 -0
- data/lib/everywhere/asset_catalog.rb +185 -0
- data/lib/everywhere/auth_handoff.rb +398 -0
- data/lib/everywhere/auth_token.rb +118 -0
- data/lib/everywhere/builders/android.rb +844 -0
- data/lib/everywhere/builders/ios.rb +40 -3
- data/lib/everywhere/commands/build.rb +51 -9
- data/lib/everywhere/commands/clean.rb +10 -5
- data/lib/everywhere/commands/dev.rb +46 -8
- data/lib/everywhere/commands/doctor.rb +89 -3
- data/lib/everywhere/commands/install.rb +1 -1
- data/lib/everywhere/commands/logs.rb +117 -8
- data/lib/everywhere/config.rb +409 -13
- data/lib/everywhere/emulator.rb +405 -0
- data/lib/everywhere/engine.rb +12 -0
- data/lib/everywhere/icon.rb +196 -0
- data/lib/everywhere/log_filter.rb +74 -0
- data/lib/everywhere/native_helper.rb +2 -5
- data/lib/everywhere/omniauth.rb +88 -0
- data/lib/everywhere/paths.rb +47 -0
- data/lib/everywhere/version.rb +1 -1
- data/support/mobile/android/README.md +217 -0
- data/support/mobile/android/app/build.gradle.kts +156 -0
- data/support/mobile/android/app/everywhere.properties +8 -0
- data/support/mobile/android/app/native-packages.gradle.kts +16 -0
- data/support/mobile/android/app/proguard-rules.pro +21 -0
- data/support/mobile/android/app/src/debug/res/xml/network_security_config.xml +30 -0
- data/support/mobile/android/app/src/main/AndroidManifest.xml +42 -0
- data/support/mobile/android/app/src/main/assets/everywhere.json +9 -0
- data/support/mobile/android/app/src/main/assets/fonts/MaterialIcons-Regular.codepoints +2235 -0
- data/support/mobile/android/app/src/main/assets/fonts/MaterialIcons-Regular.ttf +0 -0
- data/support/mobile/android/app/src/main/assets/json/path-configuration.json +19 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/AuthFlow.kt +268 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/EverywhereApplication.kt +178 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/EverywhereConfig.kt +409 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/EverywhereEvents.kt +68 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/EverywhereHost.kt +101 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/IconFont.kt +211 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/MainActivity.kt +975 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/MainTabs.kt +201 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/WebBottomSheetFragment.kt +13 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/WebFragment.kt +36 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/BiometricsComponent.kt +535 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/HapticsComponent.kt +141 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/MenuComponent.kt +361 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/NotificationComponent.kt +151 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/PermissionsComponent.kt +271 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/StorageComponent.kt +101 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/WebControlChannel.kt +204 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/extensions/EverywhereExtensions.kt +51 -0
- data/support/mobile/android/app/src/main/res/color/bottom_navigation_active_indicator.xml +4 -0
- data/support/mobile/android/app/src/main/res/color/bottom_navigation_item.xml +11 -0
- data/support/mobile/android/app/src/main/res/drawable/ic_launcher_foreground.xml +26 -0
- data/support/mobile/android/app/src/main/res/drawable/ic_tab_placeholder.xml +28 -0
- data/support/mobile/android/app/src/main/res/layout/activity_main.xml +116 -0
- data/support/mobile/android/app/src/main/res/layout/bridge_menu_sheet.xml +83 -0
- data/support/mobile/android/app/src/main/res/layout/bridge_menu_sheet_item.xml +35 -0
- data/support/mobile/android/app/src/main/res/layout/tab_more_sheet.xml +48 -0
- data/support/mobile/android/app/src/main/res/layout/tab_more_sheet_item.xml +35 -0
- data/support/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +12 -0
- data/support/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
- data/support/mobile/android/app/src/main/res/values/colors.xml +21 -0
- data/support/mobile/android/app/src/main/res/values/ic_launcher_background.xml +5 -0
- data/support/mobile/android/app/src/main/res/values/strings.xml +18 -0
- data/support/mobile/android/app/src/main/res/values/styles.xml +32 -0
- data/support/mobile/android/app/src/main/res/values/themes.xml +53 -0
- data/support/mobile/android/app/src/main/res/values-night/colors.xml +11 -0
- data/support/mobile/android/app/src/main/res/values-night/themes.xml +33 -0
- data/support/mobile/android/app/src/main/res/xml/network_security_config.xml +12 -0
- data/support/mobile/android/app/src/stamped/AndroidManifest.xml +34 -0
- data/support/mobile/android/build.gradle.kts +8 -0
- data/support/mobile/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/support/mobile/android/gradle/wrapper/gradle-wrapper.properties +10 -0
- data/support/mobile/android/gradle.properties +14 -0
- data/support/mobile/android/gradlew +251 -0
- data/support/mobile/android/gradlew.bat +94 -0
- data/support/mobile/android/settings.gradle.kts +28 -0
- data/support/mobile/ios/App/AppDelegate.swift +5 -0
- data/support/mobile/ios/App/AuthFlow.swift +101 -0
- data/support/mobile/ios/App/EverywhereConfig.swift +84 -0
- data/support/mobile/ios/App/SceneDelegate.swift +103 -0
- data/support/mobile/ios/App.xcodeproj/project.pbxproj +4 -0
- data/support/mobile/ios/README.md +4 -1
- metadata +67 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
A deliberately blank 24dp drawable, and the only reason it exists:
|
|
4
|
+
`HotwireBottomTab.iconResId` is an `@DrawableRes Int`, so there is no way to
|
|
5
|
+
hand the controller the bitmap IconFont renders. `loadMenu()` calls
|
|
6
|
+
`setIcon(iconResId)` before we can intervene and an invalid id throws, so
|
|
7
|
+
every tab is built with this placeholder and MainActivity overwrites
|
|
8
|
+
`bottomNav.menu.getItem(i).icon` immediately after each `load()`.
|
|
9
|
+
|
|
10
|
+
It draws nothing rather than a fallback glyph because it is never meant to be
|
|
11
|
+
seen: if it ever shows up on a tab, the icon re-apply pass was skipped.
|
|
12
|
+
|
|
13
|
+
The transparent path below is REQUIRED, not decoration. A <vector> with no
|
|
14
|
+
<path> compiles cleanly through aapt2 and then throws
|
|
15
|
+
`XmlPullParserException: no path defined` when the device inflates it — which
|
|
16
|
+
means the crash lands in MainActivity.applyTabs at launch, on every app that
|
|
17
|
+
declares a tab, with a stack trace that names VectorDrawable rather than this
|
|
18
|
+
file. Keep a path here.
|
|
19
|
+
-->
|
|
20
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
21
|
+
android:width="24dp"
|
|
22
|
+
android:height="24dp"
|
|
23
|
+
android:viewportWidth="24"
|
|
24
|
+
android:viewportHeight="24">
|
|
25
|
+
<path
|
|
26
|
+
android:fillColor="#00000000"
|
|
27
|
+
android:pathData="M0,0h24v24h-24z" />
|
|
28
|
+
</vector>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
FROZEN, and the reason MainTabs exists.
|
|
4
|
+
|
|
5
|
+
A HotwireBottomTab needs a real FragmentContainerView id, and NavigatorHost
|
|
6
|
+
resolves its configuration once in onCreate. Tabs, however, arrive at runtime
|
|
7
|
+
from the server's path configuration and are auth-gated, so the shell cannot
|
|
8
|
+
know how many there will be. The answer is a fixed pool: five hosts declared
|
|
9
|
+
here (Material bottom navigation tops out at five items anyway), with the
|
|
10
|
+
resolved tabs mapped onto them and every unused slot expressed as
|
|
11
|
+
`isVisible = false`.
|
|
12
|
+
|
|
13
|
+
Two rules follow from that and are enforced in MainTabs/MainActivity:
|
|
14
|
+
* navigatorConfigurations() must return a configuration for ALL FIVE hosts
|
|
15
|
+
on every launch, or NavigatorHost.onCreate throws IllegalStateException
|
|
16
|
+
for each slot it can't find one for.
|
|
17
|
+
* `lazyLoadTabs = true` is mandatory, or all five hosts cold-boot a WebView
|
|
18
|
+
and fetch their start location at launch — including the hidden,
|
|
19
|
+
auth-gated ones.
|
|
20
|
+
|
|
21
|
+
The splash overlay is a sibling of the hosts rather than a separate window
|
|
22
|
+
(iOS uses a second UIWindow): an Activity has one content view, and the
|
|
23
|
+
bottom navigation is rebuilt underneath the overlay, not around it.
|
|
24
|
+
-->
|
|
25
|
+
<androidx.constraintlayout.widget.ConstraintLayout
|
|
26
|
+
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
27
|
+
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
28
|
+
xmlns:tools="http://schemas.android.com/tools"
|
|
29
|
+
android:id="@+id/root"
|
|
30
|
+
android:layout_width="match_parent"
|
|
31
|
+
android:layout_height="match_parent"
|
|
32
|
+
tools:context=".MainActivity">
|
|
33
|
+
|
|
34
|
+
<androidx.fragment.app.FragmentContainerView
|
|
35
|
+
android:id="@+id/navigator_host_1"
|
|
36
|
+
android:name="dev.hotwire.navigation.navigator.NavigatorHost"
|
|
37
|
+
android:layout_width="match_parent"
|
|
38
|
+
android:layout_height="0dp"
|
|
39
|
+
app:defaultNavHost="false"
|
|
40
|
+
app:layout_constraintBottom_toTopOf="@id/bottom_nav"
|
|
41
|
+
app:layout_constraintTop_toTopOf="parent" />
|
|
42
|
+
|
|
43
|
+
<androidx.fragment.app.FragmentContainerView
|
|
44
|
+
android:id="@+id/navigator_host_2"
|
|
45
|
+
android:name="dev.hotwire.navigation.navigator.NavigatorHost"
|
|
46
|
+
android:layout_width="match_parent"
|
|
47
|
+
android:layout_height="0dp"
|
|
48
|
+
app:defaultNavHost="false"
|
|
49
|
+
app:layout_constraintBottom_toTopOf="@id/bottom_nav"
|
|
50
|
+
app:layout_constraintTop_toTopOf="parent" />
|
|
51
|
+
|
|
52
|
+
<androidx.fragment.app.FragmentContainerView
|
|
53
|
+
android:id="@+id/navigator_host_3"
|
|
54
|
+
android:name="dev.hotwire.navigation.navigator.NavigatorHost"
|
|
55
|
+
android:layout_width="match_parent"
|
|
56
|
+
android:layout_height="0dp"
|
|
57
|
+
app:defaultNavHost="false"
|
|
58
|
+
app:layout_constraintBottom_toTopOf="@id/bottom_nav"
|
|
59
|
+
app:layout_constraintTop_toTopOf="parent" />
|
|
60
|
+
|
|
61
|
+
<androidx.fragment.app.FragmentContainerView
|
|
62
|
+
android:id="@+id/navigator_host_4"
|
|
63
|
+
android:name="dev.hotwire.navigation.navigator.NavigatorHost"
|
|
64
|
+
android:layout_width="match_parent"
|
|
65
|
+
android:layout_height="0dp"
|
|
66
|
+
app:defaultNavHost="false"
|
|
67
|
+
app:layout_constraintBottom_toTopOf="@id/bottom_nav"
|
|
68
|
+
app:layout_constraintTop_toTopOf="parent" />
|
|
69
|
+
|
|
70
|
+
<androidx.fragment.app.FragmentContainerView
|
|
71
|
+
android:id="@+id/navigator_host_5"
|
|
72
|
+
android:name="dev.hotwire.navigation.navigator.NavigatorHost"
|
|
73
|
+
android:layout_width="match_parent"
|
|
74
|
+
android:layout_height="0dp"
|
|
75
|
+
app:defaultNavHost="false"
|
|
76
|
+
app:layout_constraintBottom_toTopOf="@id/bottom_nav"
|
|
77
|
+
app:layout_constraintTop_toTopOf="parent" />
|
|
78
|
+
|
|
79
|
+
<com.google.android.material.bottomnavigation.BottomNavigationView
|
|
80
|
+
android:id="@+id/bottom_nav"
|
|
81
|
+
android:layout_width="match_parent"
|
|
82
|
+
android:layout_height="wrap_content"
|
|
83
|
+
app:labelVisibilityMode="labeled"
|
|
84
|
+
app:layout_constraintBottom_toBottomOf="parent"
|
|
85
|
+
app:layout_constraintEnd_toEndOf="parent"
|
|
86
|
+
app:layout_constraintStart_toStartOf="parent" />
|
|
87
|
+
|
|
88
|
+
<!--
|
|
89
|
+
Continues the themed launch background over the first page load, so the
|
|
90
|
+
app never shows a white gap while the first request is in flight. Sits
|
|
91
|
+
above everything, including the bottom navigation, and is removed by
|
|
92
|
+
MainActivity.dismissSplash().
|
|
93
|
+
-->
|
|
94
|
+
<FrameLayout
|
|
95
|
+
android:id="@+id/splash"
|
|
96
|
+
android:layout_width="0dp"
|
|
97
|
+
android:layout_height="0dp"
|
|
98
|
+
android:background="?android:attr/colorBackground"
|
|
99
|
+
android:clickable="true"
|
|
100
|
+
android:focusable="true"
|
|
101
|
+
android:elevation="16dp"
|
|
102
|
+
app:layout_constraintBottom_toBottomOf="parent"
|
|
103
|
+
app:layout_constraintEnd_toEndOf="parent"
|
|
104
|
+
app:layout_constraintStart_toStartOf="parent"
|
|
105
|
+
app:layout_constraintTop_toTopOf="parent">
|
|
106
|
+
|
|
107
|
+
<ProgressBar
|
|
108
|
+
android:id="@+id/splash_progress"
|
|
109
|
+
style="?android:attr/progressBarStyle"
|
|
110
|
+
android:layout_width="wrap_content"
|
|
111
|
+
android:layout_height="wrap_content"
|
|
112
|
+
android:layout_gravity="center" />
|
|
113
|
+
|
|
114
|
+
</FrameLayout>
|
|
115
|
+
|
|
116
|
+
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
Action sheet for the `everywhere` menu bridge component: both the `menu`
|
|
4
|
+
event (Everywhere.menu / data-everywhere-menu) and a nav item's pull-down.
|
|
5
|
+
|
|
6
|
+
Deliberately built from framework widgets and theme attributes only — no
|
|
7
|
+
colors.xml, no dimens.xml, no styles of its own. The rest of res/ belongs to
|
|
8
|
+
the shell template and is stamped per app, so anything this file referenced
|
|
9
|
+
there would be a second place a brand colour has to be right. Every colour
|
|
10
|
+
below comes from the running theme, which makes light and dark automatic.
|
|
11
|
+
-->
|
|
12
|
+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
13
|
+
android:layout_width="match_parent"
|
|
14
|
+
android:layout_height="wrap_content"
|
|
15
|
+
android:orientation="vertical"
|
|
16
|
+
android:paddingTop="8dp"
|
|
17
|
+
android:paddingBottom="8dp">
|
|
18
|
+
|
|
19
|
+
<LinearLayout
|
|
20
|
+
android:id="@+id/bridge_menu_header"
|
|
21
|
+
android:layout_width="match_parent"
|
|
22
|
+
android:layout_height="wrap_content"
|
|
23
|
+
android:orientation="vertical"
|
|
24
|
+
android:paddingStart="24dp"
|
|
25
|
+
android:paddingEnd="24dp"
|
|
26
|
+
android:paddingTop="12dp"
|
|
27
|
+
android:paddingBottom="12dp">
|
|
28
|
+
|
|
29
|
+
<TextView
|
|
30
|
+
android:id="@+id/bridge_menu_title"
|
|
31
|
+
android:layout_width="match_parent"
|
|
32
|
+
android:layout_height="wrap_content"
|
|
33
|
+
android:textColor="?android:attr/textColorPrimary"
|
|
34
|
+
android:textSize="16sp"
|
|
35
|
+
android:textStyle="bold" />
|
|
36
|
+
|
|
37
|
+
<TextView
|
|
38
|
+
android:id="@+id/bridge_menu_message"
|
|
39
|
+
android:layout_width="match_parent"
|
|
40
|
+
android:layout_height="wrap_content"
|
|
41
|
+
android:layout_marginTop="4dp"
|
|
42
|
+
android:textColor="?android:attr/textColorSecondary"
|
|
43
|
+
android:textSize="14sp" />
|
|
44
|
+
</LinearLayout>
|
|
45
|
+
|
|
46
|
+
<ScrollView
|
|
47
|
+
android:layout_width="match_parent"
|
|
48
|
+
android:layout_height="wrap_content"
|
|
49
|
+
android:scrollbarStyle="outsideOverlay">
|
|
50
|
+
|
|
51
|
+
<LinearLayout
|
|
52
|
+
android:id="@+id/bridge_menu_items"
|
|
53
|
+
android:layout_width="match_parent"
|
|
54
|
+
android:layout_height="wrap_content"
|
|
55
|
+
android:orientation="vertical" />
|
|
56
|
+
</ScrollView>
|
|
57
|
+
|
|
58
|
+
<View
|
|
59
|
+
android:layout_width="match_parent"
|
|
60
|
+
android:layout_height="1dp"
|
|
61
|
+
android:layout_marginTop="8dp"
|
|
62
|
+
android:layout_marginBottom="8dp"
|
|
63
|
+
android:background="?android:attr/listDivider" />
|
|
64
|
+
|
|
65
|
+
<!--
|
|
66
|
+
Always present, like the cancel action iOS adds to every action sheet.
|
|
67
|
+
A pull-down menu simply ignores the resulting dismiss.
|
|
68
|
+
-->
|
|
69
|
+
<TextView
|
|
70
|
+
android:id="@+id/bridge_menu_cancel"
|
|
71
|
+
android:layout_width="match_parent"
|
|
72
|
+
android:layout_height="wrap_content"
|
|
73
|
+
android:background="?android:attr/selectableItemBackground"
|
|
74
|
+
android:clickable="true"
|
|
75
|
+
android:focusable="true"
|
|
76
|
+
android:gravity="center_vertical"
|
|
77
|
+
android:minHeight="56dp"
|
|
78
|
+
android:paddingStart="24dp"
|
|
79
|
+
android:paddingEnd="24dp"
|
|
80
|
+
android:text="@android:string/cancel"
|
|
81
|
+
android:textColor="?android:attr/textColorSecondary"
|
|
82
|
+
android:textSize="16sp" />
|
|
83
|
+
</LinearLayout>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
One row of the `everywhere` menu action sheet. The icon slot is kept (and
|
|
4
|
+
hidden rather than removed) whenever any sibling row has an icon, so a mixed
|
|
5
|
+
list still lines its titles up — the same alignment a UIMenu gives on iOS.
|
|
6
|
+
|
|
7
|
+
Theme attributes only; see bridge_menu_sheet.xml for why.
|
|
8
|
+
-->
|
|
9
|
+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
10
|
+
android:layout_width="match_parent"
|
|
11
|
+
android:layout_height="wrap_content"
|
|
12
|
+
android:background="?android:attr/selectableItemBackground"
|
|
13
|
+
android:clickable="true"
|
|
14
|
+
android:focusable="true"
|
|
15
|
+
android:gravity="center_vertical"
|
|
16
|
+
android:minHeight="56dp"
|
|
17
|
+
android:orientation="horizontal"
|
|
18
|
+
android:paddingStart="24dp"
|
|
19
|
+
android:paddingEnd="24dp">
|
|
20
|
+
|
|
21
|
+
<ImageView
|
|
22
|
+
android:id="@+id/bridge_menu_item_icon"
|
|
23
|
+
android:layout_width="24dp"
|
|
24
|
+
android:layout_height="24dp"
|
|
25
|
+
android:layout_marginEnd="24dp"
|
|
26
|
+
android:importantForAccessibility="no"
|
|
27
|
+
android:visibility="gone" />
|
|
28
|
+
|
|
29
|
+
<TextView
|
|
30
|
+
android:id="@+id/bridge_menu_item_title"
|
|
31
|
+
android:layout_width="match_parent"
|
|
32
|
+
android:layout_height="wrap_content"
|
|
33
|
+
android:textColor="?android:attr/textColorPrimary"
|
|
34
|
+
android:textSize="16sp" />
|
|
35
|
+
</LinearLayout>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
The "More" tab's contents: every tab past the fourth, which Android's
|
|
4
|
+
BottomNavigationView has no room for and, unlike iOS's UITabBarController,
|
|
5
|
+
synthesises no home for. MainActivity fills this in from the arrangement.
|
|
6
|
+
|
|
7
|
+
Framework widgets and theme attributes only, no colors.xml and no styles of
|
|
8
|
+
its own. The rest of res/ belongs to the shell template and is stamped per
|
|
9
|
+
app, so anything referenced from here would be a second place a brand colour
|
|
10
|
+
has to be right. Every colour below comes from the running theme, which makes
|
|
11
|
+
light and dark automatic.
|
|
12
|
+
-->
|
|
13
|
+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
14
|
+
android:layout_width="match_parent"
|
|
15
|
+
android:layout_height="wrap_content"
|
|
16
|
+
android:orientation="vertical"
|
|
17
|
+
android:paddingTop="8dp"
|
|
18
|
+
android:paddingBottom="8dp">
|
|
19
|
+
|
|
20
|
+
<TextView
|
|
21
|
+
android:id="@+id/tab_more_sheet_title"
|
|
22
|
+
android:layout_width="match_parent"
|
|
23
|
+
android:layout_height="wrap_content"
|
|
24
|
+
android:paddingStart="24dp"
|
|
25
|
+
android:paddingEnd="24dp"
|
|
26
|
+
android:paddingTop="12dp"
|
|
27
|
+
android:paddingBottom="12dp"
|
|
28
|
+
android:textColor="?android:attr/textColorPrimary"
|
|
29
|
+
android:textSize="16sp"
|
|
30
|
+
android:textStyle="bold" />
|
|
31
|
+
|
|
32
|
+
<!--
|
|
33
|
+
Scrolls because the overflow has no upper bound: five tabs fit the bar,
|
|
34
|
+
and everything after that arrives here however many there are.
|
|
35
|
+
-->
|
|
36
|
+
<ScrollView
|
|
37
|
+
android:layout_width="match_parent"
|
|
38
|
+
android:layout_height="wrap_content"
|
|
39
|
+
android:scrollbarStyle="outsideOverlay">
|
|
40
|
+
|
|
41
|
+
<LinearLayout
|
|
42
|
+
android:id="@+id/tab_more_sheet_items"
|
|
43
|
+
android:layout_width="match_parent"
|
|
44
|
+
android:layout_height="wrap_content"
|
|
45
|
+
android:orientation="vertical" />
|
|
46
|
+
</ScrollView>
|
|
47
|
+
|
|
48
|
+
</LinearLayout>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
One overflow tab in the More sheet: its icon and its title, the same two
|
|
4
|
+
things it would have shown in the bar.
|
|
5
|
+
|
|
6
|
+
The icon slot is always present, never hidden, because every tab has an icon
|
|
7
|
+
(MainTabs defaults a missing one to `circle`, and the builder rejects a name
|
|
8
|
+
the font doesn't carry). Theme attributes only; see tab_more_sheet.xml.
|
|
9
|
+
-->
|
|
10
|
+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
11
|
+
android:layout_width="match_parent"
|
|
12
|
+
android:layout_height="wrap_content"
|
|
13
|
+
android:background="?android:attr/selectableItemBackground"
|
|
14
|
+
android:clickable="true"
|
|
15
|
+
android:focusable="true"
|
|
16
|
+
android:gravity="center_vertical"
|
|
17
|
+
android:minHeight="56dp"
|
|
18
|
+
android:orientation="horizontal"
|
|
19
|
+
android:paddingStart="24dp"
|
|
20
|
+
android:paddingEnd="24dp">
|
|
21
|
+
|
|
22
|
+
<ImageView
|
|
23
|
+
android:id="@+id/tab_more_sheet_item_icon"
|
|
24
|
+
android:layout_width="24dp"
|
|
25
|
+
android:layout_height="24dp"
|
|
26
|
+
android:layout_marginEnd="24dp"
|
|
27
|
+
android:importantForAccessibility="no" />
|
|
28
|
+
|
|
29
|
+
<TextView
|
|
30
|
+
android:id="@+id/tab_more_sheet_item_title"
|
|
31
|
+
android:layout_width="match_parent"
|
|
32
|
+
android:layout_height="wrap_content"
|
|
33
|
+
android:textColor="?android:attr/textColorPrimary"
|
|
34
|
+
android:textSize="16sp" />
|
|
35
|
+
</LinearLayout>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
minSdk 28 means every device that can install this app understands adaptive
|
|
4
|
+
icons, so there are no legacy mipmap-<dpi>/ic_launcher.png fallbacks to
|
|
5
|
+
generate — the two layers below are the whole launcher icon. The builder
|
|
6
|
+
stamps the layers, never this file.
|
|
7
|
+
-->
|
|
8
|
+
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
9
|
+
<background android:drawable="@color/ic_launcher_background" />
|
|
10
|
+
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
|
11
|
+
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
|
12
|
+
</adaptive-icon>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
3
|
+
<background android:drawable="@color/ic_launcher_background" />
|
|
4
|
+
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
|
5
|
+
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
|
6
|
+
</adaptive-icon>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
STAMPED by `every build` for Android from `appearance.tint_color` and
|
|
4
|
+
`appearance.background_color`. The light half lives here, the dark half in
|
|
5
|
+
values-night/colors.xml — an app that gives a single hex gets the same value
|
|
6
|
+
written to both, which is exactly how iOS's ThemedColor collapses.
|
|
7
|
+
|
|
8
|
+
Everything else in the theme derives from these two, so branding an app is
|
|
9
|
+
two colours and nothing more.
|
|
10
|
+
-->
|
|
11
|
+
<resources>
|
|
12
|
+
<color name="everywhere_tint">#5321FC</color>
|
|
13
|
+
<color name="everywhere_background">#FFFFFF</color>
|
|
14
|
+
|
|
15
|
+
<color name="everywhere_on_tint">#FFFFFF</color>
|
|
16
|
+
<color name="everywhere_on_background">#000000</color>
|
|
17
|
+
<color name="everywhere_error">#B00020</color>
|
|
18
|
+
<color name="everywhere_on_error">#FFFFFF</color>
|
|
19
|
+
|
|
20
|
+
<color name="everywhere_transparent">#00000000</color>
|
|
21
|
+
</resources>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
FROZEN. The app's own name is NOT here: it arrives as the
|
|
4
|
+
`everywhereLabel` manifest placeholder from everywhere.properties, so
|
|
5
|
+
renaming an app never touches a resource file. Only shell-owned UI strings
|
|
6
|
+
live here.
|
|
7
|
+
-->
|
|
8
|
+
<resources>
|
|
9
|
+
<string name="everywhere_auth_failed_title">Sign-in didn\'t finish</string>
|
|
10
|
+
<string name="everywhere_auth_failed_message">Something went wrong on the way back to the app. Please try again.</string>
|
|
11
|
+
<string name="everywhere_ok">OK</string>
|
|
12
|
+
<!--
|
|
13
|
+
The fifth bar item when an app declares more than five tabs, and the
|
|
14
|
+
heading of the sheet listing the rest. Matches what UITabBarController
|
|
15
|
+
names its own overflow tab on iOS.
|
|
16
|
+
-->
|
|
17
|
+
<string name="everywhere_more_tab">More</string>
|
|
18
|
+
</resources>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!-- FROZEN. Component styles; all colour comes from the theme attributes. -->
|
|
3
|
+
<resources>
|
|
4
|
+
|
|
5
|
+
<style name="Widget.Everywhere.BottomNavigationView" parent="Widget.MaterialComponents.BottomNavigationView">
|
|
6
|
+
<item name="android:background">?colorSurface</item>
|
|
7
|
+
<item name="itemBackground">?colorSurface</item>
|
|
8
|
+
<item name="backgroundTint">@null</item>
|
|
9
|
+
<item name="elevation">8dp</item>
|
|
10
|
+
<!-- Tab icons are runtime-rendered bitmaps (IconFont), so the tint has
|
|
11
|
+
to come from a ColorStateList the widget applies to whatever
|
|
12
|
+
Drawable it is handed — that is what makes a font-drawn glyph
|
|
13
|
+
respond to selection and to dark mode at all. -->
|
|
14
|
+
<item name="itemIconTint">@color/bottom_navigation_item</item>
|
|
15
|
+
<item name="itemTextColor">@color/bottom_navigation_item</item>
|
|
16
|
+
<item name="itemActiveIndicatorStyle">@style/Widget.Everywhere.BottomNavigationView.ActiveIndicator</item>
|
|
17
|
+
</style>
|
|
18
|
+
|
|
19
|
+
<style name="Widget.Everywhere.BottomNavigationView.ActiveIndicator" parent="">
|
|
20
|
+
<item name="android:width">64dp</item>
|
|
21
|
+
<item name="android:height">32dp</item>
|
|
22
|
+
<item name="marginHorizontal">4dp</item>
|
|
23
|
+
<item name="android:color">@color/bottom_navigation_active_indicator</item>
|
|
24
|
+
</style>
|
|
25
|
+
|
|
26
|
+
<style name="Widget.Everywhere.Toolbar" parent="Widget.MaterialComponents.Toolbar.Surface">
|
|
27
|
+
<item name="android:background">?colorSurface</item>
|
|
28
|
+
<item name="colorControlNormal">?colorOnSurface</item>
|
|
29
|
+
<item name="titleTextColor">?colorOnSurface</item>
|
|
30
|
+
</style>
|
|
31
|
+
|
|
32
|
+
</resources>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
FROZEN. Everything visible derives from the two stamped colours in
|
|
4
|
+
colors.xml, so branding never edits a theme.
|
|
5
|
+
|
|
6
|
+
Parent is Theme.MaterialComponents, not Theme.Material3, on purpose:
|
|
7
|
+
navigation-fragments 1.3.0's own layouts style themselves with
|
|
8
|
+
TextAppearance.MaterialComponents.* and this is the combination the Phase 0
|
|
9
|
+
spike actually ran on a device.
|
|
10
|
+
-->
|
|
11
|
+
<resources xmlns:tools="http://schemas.android.com/tools">
|
|
12
|
+
|
|
13
|
+
<style name="Theme.Everywhere" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
|
14
|
+
<item name="colorPrimary">@color/everywhere_tint</item>
|
|
15
|
+
<item name="colorPrimaryVariant">@color/everywhere_tint</item>
|
|
16
|
+
<item name="colorSecondary">@color/everywhere_tint</item>
|
|
17
|
+
<item name="colorSecondaryVariant">@color/everywhere_tint</item>
|
|
18
|
+
<item name="colorAccent">@color/everywhere_tint</item>
|
|
19
|
+
|
|
20
|
+
<item name="android:colorBackground">@color/everywhere_background</item>
|
|
21
|
+
<item name="colorSurface">@color/everywhere_background</item>
|
|
22
|
+
<item name="colorError">@color/everywhere_error</item>
|
|
23
|
+
|
|
24
|
+
<item name="colorOnPrimary">@color/everywhere_on_tint</item>
|
|
25
|
+
<item name="colorOnSecondary">@color/everywhere_on_tint</item>
|
|
26
|
+
<item name="colorOnBackground">@color/everywhere_on_background</item>
|
|
27
|
+
<item name="colorOnSurface">@color/everywhere_on_background</item>
|
|
28
|
+
<item name="colorOnError">@color/everywhere_on_error</item>
|
|
29
|
+
|
|
30
|
+
<!-- Edge-to-edge: the bottom navigation applies the system-bar insets
|
|
31
|
+
itself (HotwireBottomNavigationController.applyWindowInsets). -->
|
|
32
|
+
<item name="android:statusBarColor">@color/everywhere_transparent</item>
|
|
33
|
+
<item name="android:navigationBarColor">@color/everywhere_transparent</item>
|
|
34
|
+
<item name="android:windowLightStatusBar">true</item>
|
|
35
|
+
<item name="android:windowLightNavigationBar" tools:ignore="NewApi">true</item>
|
|
36
|
+
|
|
37
|
+
<item name="elevationOverlayEnabled">false</item>
|
|
38
|
+
<item name="bottomNavigationStyle">@style/Widget.Everywhere.BottomNavigationView</item>
|
|
39
|
+
<item name="toolbarStyle">@style/Widget.Everywhere.Toolbar</item>
|
|
40
|
+
</style>
|
|
41
|
+
|
|
42
|
+
<!--
|
|
43
|
+
The Activity's launch theme. windowBackground is the stamped background
|
|
44
|
+
colour, so the system's starting window, the splash overlay in
|
|
45
|
+
activity_main.xml and the first rendered page are all the same colour and
|
|
46
|
+
the launch reads as one continuous surface. MainActivity swaps to
|
|
47
|
+
Theme.Everywhere in onCreate, before setContentView.
|
|
48
|
+
-->
|
|
49
|
+
<style name="Theme.Everywhere.Splash" parent="Theme.Everywhere">
|
|
50
|
+
<item name="android:windowBackground">@color/everywhere_background</item>
|
|
51
|
+
</style>
|
|
52
|
+
|
|
53
|
+
</resources>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!-- STAMPED — the dark half of appearance.tint_color / background_color. -->
|
|
3
|
+
<resources>
|
|
4
|
+
<color name="everywhere_tint">#7A75FF</color>
|
|
5
|
+
<color name="everywhere_background">#121212</color>
|
|
6
|
+
|
|
7
|
+
<color name="everywhere_on_tint">#000000</color>
|
|
8
|
+
<color name="everywhere_on_background">#FFFFFF</color>
|
|
9
|
+
<color name="everywhere_error">#CF6679</color>
|
|
10
|
+
<color name="everywhere_on_error">#000000</color>
|
|
11
|
+
</resources>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
The colours themselves come from values-night/colors.xml, so the only thing
|
|
4
|
+
that changes here is which system-bar icon set stays legible.
|
|
5
|
+
-->
|
|
6
|
+
<resources>
|
|
7
|
+
<style name="Theme.Everywhere" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
|
8
|
+
<item name="colorPrimary">@color/everywhere_tint</item>
|
|
9
|
+
<item name="colorPrimaryVariant">@color/everywhere_tint</item>
|
|
10
|
+
<item name="colorSecondary">@color/everywhere_tint</item>
|
|
11
|
+
<item name="colorSecondaryVariant">@color/everywhere_tint</item>
|
|
12
|
+
<item name="colorAccent">@color/everywhere_tint</item>
|
|
13
|
+
|
|
14
|
+
<item name="android:colorBackground">@color/everywhere_background</item>
|
|
15
|
+
<item name="colorSurface">@color/everywhere_background</item>
|
|
16
|
+
<item name="colorError">@color/everywhere_error</item>
|
|
17
|
+
|
|
18
|
+
<item name="colorOnPrimary">@color/everywhere_on_tint</item>
|
|
19
|
+
<item name="colorOnSecondary">@color/everywhere_on_tint</item>
|
|
20
|
+
<item name="colorOnBackground">@color/everywhere_on_background</item>
|
|
21
|
+
<item name="colorOnSurface">@color/everywhere_on_background</item>
|
|
22
|
+
<item name="colorOnError">@color/everywhere_on_error</item>
|
|
23
|
+
|
|
24
|
+
<item name="android:statusBarColor">@color/everywhere_transparent</item>
|
|
25
|
+
<item name="android:navigationBarColor">@color/everywhere_transparent</item>
|
|
26
|
+
<item name="android:windowLightStatusBar">false</item>
|
|
27
|
+
<item name="android:windowLightNavigationBar">false</item>
|
|
28
|
+
|
|
29
|
+
<item name="elevationOverlayEnabled">false</item>
|
|
30
|
+
<item name="bottomNavigationStyle">@style/Widget.Everywhere.BottomNavigationView</item>
|
|
31
|
+
<item name="toolbarStyle">@style/Widget.Everywhere.Toolbar</item>
|
|
32
|
+
</style>
|
|
33
|
+
</resources>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
Release baseline: no cleartext, anywhere. The debug build type overlays
|
|
4
|
+
src/debug/res/xml/network_security_config.xml over this file (same resource
|
|
5
|
+
name, build-type source set wins), which opens up loopback and the emulator's
|
|
6
|
+
host alias for `every dev` for Android. Overlaying the resource rather than the
|
|
7
|
+
manifest attribute keeps src/main/AndroidManifest.xml frozen and leaves the
|
|
8
|
+
build type's manifest slot free for src/stamped/AndroidManifest.xml.
|
|
9
|
+
-->
|
|
10
|
+
<network-security-config>
|
|
11
|
+
<base-config cleartextTrafficPermitted="false" />
|
|
12
|
+
</network-security-config>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
GENERATED by `every build` for Android. The checked-in copy is empty so the raw
|
|
4
|
+
template builds unchanged; the CLI rewrites it whenever everywhere.yml
|
|
5
|
+
declares `deep_linking:`, `auth:` or `permissions:`.
|
|
6
|
+
|
|
7
|
+
It is applied as BOTH build types' manifest (see app/build.gradle.kts) rather
|
|
8
|
+
than being folded into the main manifest, so the frozen file above never
|
|
9
|
+
needs editing — the analogue of iOS's optional App.entitlements.
|
|
10
|
+
|
|
11
|
+
Generated content looks like:
|
|
12
|
+
|
|
13
|
+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
14
|
+
|
|
15
|
+
<application>
|
|
16
|
+
<activity android:name="com.rubyeverywhere.shell.MainActivity">
|
|
17
|
+
<intent-filter android:autoVerify="true">
|
|
18
|
+
<action android:name="android.intent.action.VIEW" />
|
|
19
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
20
|
+
<category android:name="android.intent.category.BROWSABLE" />
|
|
21
|
+
<data android:scheme="https" android:host="example.com" />
|
|
22
|
+
</intent-filter>
|
|
23
|
+
<intent-filter>
|
|
24
|
+
<action android:name="android.intent.action.VIEW" />
|
|
25
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
26
|
+
<category android:name="android.intent.category.BROWSABLE" />
|
|
27
|
+
<data android:scheme="com.example.app" />
|
|
28
|
+
</intent-filter>
|
|
29
|
+
</activity>
|
|
30
|
+
</application>
|
|
31
|
+
-->
|
|
32
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
33
|
+
<application />
|
|
34
|
+
</manifest>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Top-level build file. Plugin versions are pinned here, once, for every
|
|
2
|
+
// module — the analogue of the iOS template's committed `Package.resolved`.
|
|
3
|
+
// Moving a pin is a deliberate edit to this template, never to a stamped copy.
|
|
4
|
+
plugins {
|
|
5
|
+
id("com.android.application") version "8.13.2" apply false
|
|
6
|
+
id("org.jetbrains.kotlin.android") version "2.3.0" apply false
|
|
7
|
+
id("org.jetbrains.kotlin.plugin.serialization") version "2.3.0" apply false
|
|
8
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
distributionBase=GRADLE_USER_HOME
|
|
2
|
+
distributionPath=wrapper/dists
|
|
3
|
+
# `-bin`, not `-all`: the `-all` distribution unpacks to 522 MB in
|
|
4
|
+
# GRADLE_USER_HOME and the extra 500 MB is Gradle's own sources and javadoc,
|
|
5
|
+
# which only an IDE indexing the Gradle API ever reads. The CLI never does.
|
|
6
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
|
|
7
|
+
networkTimeout=10000
|
|
8
|
+
validateDistributionUrl=true
|
|
9
|
+
zipStoreBase=GRADLE_USER_HOME
|
|
10
|
+
zipStorePath=wrapper/dists
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Frozen build settings. Nothing per-app lives here — see app/everywhere.properties.
|
|
2
|
+
|
|
3
|
+
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|
4
|
+
org.gradle.caching=true
|
|
5
|
+
|
|
6
|
+
# Off deliberately. The configuration cache serialises the whole build model,
|
|
7
|
+
# and `app/build.gradle.kts` reads `everywhere.properties` at configuration
|
|
8
|
+
# time — a file the CLI rewrites on every build. Gradle would have to
|
|
9
|
+
# invalidate the cache each run anyway, so it buys nothing and hides staleness.
|
|
10
|
+
org.gradle.configuration-cache=false
|
|
11
|
+
|
|
12
|
+
android.useAndroidX=true
|
|
13
|
+
android.nonTransitiveRClass=true
|
|
14
|
+
kotlin.code.style=official
|